NextPowerOfTwo() public static method

public static NextPowerOfTwo ( int n ) : int
n int
return int
示例#1
0
        public void PadToPowerOfTwo()
        {
            // Ensure that the buffer's total length is a power of two.
            int n = MathUtil.NextPowerOfTwo(_samples.Count);

            PadTo(n);
        }
示例#2
0
        /// <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);
        }
        private static IEnumerator <double> WhiteFlat(int length)
        {
            // Generate "truly white" noise (flat spectrum)
            // by generating random-phase flat-magnitude in the frequency domain, then IFFT.
            // This noise is periodic - length (next power of 2 from 'n')

            int n = MathUtil.NextPowerOfTwo(length);

            Complex[] data = new Complex[n];

            double logn = Math.Log(n);

            for (int j = 0; j < n; j++)
            {
                // 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(logn * re, logn * im);
            }

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

            // Return the real component
            int k = 0;

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

                k++;
                if (k >= n)
                {
                    k = 0;
                }
            }
        }
示例#4
0
        private bool ComputePartitionedImpulseFFT()
        {
            if (_impulse == null)
            {
                return(false);
            }
            ushort nChannels;

            if (_input == null)
            {
                nChannels = _impulse.NumChannels;
            }
            else
            {
                nChannels = _input.NumChannels;
            }
            ushort p;
            int    N  = _impulseLength;
            int    Nh = N << 1;
            int    K  = (int)(N / _partitions);
            int    L  = MathUtil.NextPowerOfTwo(K << 1);
            int    P  = (int)Math.Ceiling((double)N / (double)K);

            // Initialize the arrays of impulse-FFTs
            _PartitionedImpulseFFT = new Complex[nChannels][][];
            Complex[][] tmp = new Complex[nChannels][];
            for (ushort c = 0; c < nChannels; c++)
            {
                tmp[c] = new Complex[Nh];
                _PartitionedImpulseFFT[c] = new Complex[P][];
                for (p = 0; p < P; p++)
                {
                    _PartitionedImpulseFFT[c][p] = new Complex[L];
                }
            }

            // Read all samples from the impulse, & fft in blocks of size K (padded to L, L~=2K)
            int i = 0;
            int n = 0;

            p = 0;
            foreach (ISample sample in _impulse)
            {
                // Reading a segment of the impulse (into src[])
                n++;
                if (n > _impulseLength)
                {
                    break;
                }                                  // source gave us more data than we'd expected
                for (ushort c = 0; c < _impulse.NumChannels; c++)
                {
                    tmp[c][i + K] = new Complex(sample[c], 0); // TBD
                }
                i++;
                if (i >= K)
                {
                    // Do the fft of this segment of the impulse, into fftImpulse[]
                    for (ushort c = 0; c < nChannels; c++)
                    {
                        if (c >= _impulse.NumChannels)
                        {
                            // Handle the case where impulse has only one channel, but input (hence nChannels) is wider;
                            // we already computed the fft in _PartitionedImpulseFFT[0][p], so just duplicate it.
                            // In fact we can just ref the whole buffer -- no need even to make a deep copy
                            _PartitionedImpulseFFT[c][p] = _PartitionedImpulseFFT[0][p];
                        }
                        else
                        {
                            Array.Copy(tmp[c], _PartitionedImpulseFFT[c][p], L);
                            Fourier.FFT(L, _PartitionedImpulseFFT[c][p]);
                        }
                    }
                    i = 0; p++;
                }
            }
            _impulseLengthOrig = n - 1;
            if (p < P)
            {
                // Fill any extra space with nulls
                for (int ii = i; ii < K; ii++)
                {
                    for (ushort c = 0; c < _impulse.NumChannels; c++)
                    {
                        tmp[c][ii + K] = new Complex(0, 0); // TBD
                    }
                }
                // FFT the last segment
                for (ushort c = 0; c < nChannels; c++)
                {
                    if (c >= _impulse.NumChannels)
                    {
                        // Handle the case where impulse has only one channel, but input (hence nChannels) is wider;
                        // we already computed the fft in _PartitionedImpulseFFT[0][p], so just duplicate it.
                        // In fact we can just ref the whole buffer -- no need even to make a deep copy
                        _PartitionedImpulseFFT[c][p] = _PartitionedImpulseFFT[0][p];
                    }
                    else
                    {
                        Array.Copy(tmp[c], _PartitionedImpulseFFT[c][p], L);
                        Fourier.FFT(L, _PartitionedImpulseFFT[c][p]);
                    }
                }
            }
            return(true);
        }
示例#5
0
        private void init()
        {
            _running = true;

            ComputeImpulseFFT();

            nChannels = NumChannels;
            // Size for work area
            N = _impulseLength;
            nImpulseChannels = _impulse.NumChannels;
            Nh = N << 1;

            K = (_partitions <= 0) ? N : (N / _partitions);
            L = MathUtil.NextPowerOfTwo(K << 1);
            P = (int)Math.Ceiling((double)N / (double)K);

            //              Trace.WriteLine("{0} partitions of size {1}, chunk size {2}", P, L, K);

            // Allocate buffers for the source and output
            src    = new Complex[nChannels][];
            output = new Complex[nChannels][];
            for (ushort c = 0; c < nChannels; c++)
            {
                src[c]    = new Complex[Nh];
                output[c] = new Complex[Nh];
            }

            // For partitioned convolution, allocate arrays for the fft accumulators
            if (_partitions > 0)
            {
                accum = new Complex[nChannels][][];
                for (ushort c = 0; c < nChannels; c++)
                {
                    accum[c] = new Complex[P][];
                    for (p = 0; p < P; p++)
                    {
                        accum[c][p] = new Complex[L];
                    }
                }
            }

            if (IsPersistTail)
            {
                // If there's any *unprocessed* leftover from a previous convolution,
                // load it into prevTailSamples before we begin
                if (System.IO.File.Exists(_persistFile))
                {
                    WaveReader tailReader = null;
                    try
                    {
                        tailReader      = new WaveReader(_persistFile);
                        prevTailSamples = new List <ISample>(tailReader.Iterations);
                        //                            Trace.WriteLine("Read {0} tail samples", tailReader.Iterations);
                        if (tailReader.NumChannels == NumChannels)
                        {
                            foreach (ISample s in tailReader)
                            {
                                prevTailSamples.Add(s);
                            }
                        }
                        prevTailEnum = prevTailSamples.GetEnumerator();
                    }
                    catch (Exception e)
                    {
                        Trace.WriteLine("Could not read tail {0}: {1}", _persistFile.Replace(_persistPath, ""), e.Message);
                    }
                    // finally...
//                    ThreadPool.QueueUserWorkItem(delegate(object o)
//                    {
                    try
                    {
                        if (tailReader != null)
                        {
                            tailReader.Close();
                            tailReader = null;
                        }
                        System.IO.File.Delete(_persistFile);
                    }
                    catch (Exception)
                    {
                        // ignore, we're done
                    }
//                    });
                }
            }
//              Trace.WriteLine("{0} partitions of size {1}, chunk size {2}", P, L, K);
        }
        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;
                }
            }
        }
示例#7
0
        ISoundObj CalculateSweep()
        {
            // Per http://www.anselmgoertz.de/Page10383/Monkey_Forest_dt/Manual_dt/aes-swp-english.pdf
            int fftSize = MathUtil.NextPowerOfTwo(_lengthSamples * 2);
            int N       = fftSize / 2;

            // Center the sweep in time to reduce impact of its extremities
            double fNyq   = _sr / 2;
            double FStart = _startFreq;
            double FEnd   = _endFreq;
            double SStart = (N - _lengthSamples) / 2;
            double TStart = SStart / _sr;
            double TEnd   = TStart + _lengthSecs;

            _B = (TEnd - TStart) / Math.Log(FEnd / FStart);
            _A = TStart - _B * Math.Log(FStart);

            // Make the complex spectrum
            //double ph = 0;
            double df     = (double)_sr / N;
            double phiNyq = phi(fNyq);
            double phiAdj = phiNyq % (2 * Math.PI);

            if (!_gotdata)
            {
                _data = new Complex[fftSize];
                fixed(Complex *cdata = _data)
                {
                    for (int j = 0; j < N; j++)
                    {
                        int    m  = j + 1;
                        double f  = (double)m * _sr / fftSize;
                        double ph = phi(f) - (f / fNyq) * phiAdj;
                        double v  = mag(f);
                        double Re = Math.Cos(ph) * v;
                        double Im = Math.Sin(ph) * v;
                        _data[j] = new Complex(Re, Im);
                    }
                    Fourier.IFFT(fftSize, _data, Math.Sqrt(fftSize) * _gain * MathUtil.gain(20));
                }

                // Look for values beyond the end
                // whose magnitude greater than our allowed threshold;
                // if present, window then ifft then start again.

                // Below doesn't seem to converge well
                // so just window and be done

                /*
                 * double threshold = MathUtil.gain(-90);
                 * bool iterate = true;
                 * while (iterate)
                 * {
                 *  iterate = false;
                 *  for (n = (int)(TEnd * sr + SStart * 2); n < fftSize; n++)
                 *  {
                 *      if (_data[n].Magnitude > threshold)
                 *      {
                 *          iterate = true;
                 *          break;
                 *      }
                 *  }
                 *  if (iterate)
                 *  {
                 *      Blackman bh = new Blackman((int)(_lengthSamples / 2 + SStart), _lengthSamples / 200, _lengthSamples / 2);
                 *      bh.Input = cbr;
                 *      n=0;
                 *      foreach (ISample s in bh)
                 *      {
                 *          _data[n++] = new Complex(s[0],0);
                 *      }
                 *      Fourier.FFT(fftSize, _data);
                 *      for (n = 0; n < N; n++)
                 *      {
                 *          int m = n + 1;
                 *          double f = (double)m * sr / fftSize;
                 *          double ph = _data[n].Phase;
                 *          double v = mag(f);
                 *          double Re = Math.Cos(ph) * v;
                 *          double Im = Math.Sin(ph) * v;
                 *          _data[n] = new Complex(Re, Im);
                 *      }
                 *      Fourier.IFFT(fftSize, _data);
                 *  }
                 * }
                 */

                CosWindow            bh    = new Hamming((int)(_lengthSamples / 2 + SStart), (int)(SStart), _lengthSamples / 2);
                IEnumerator <double> gains = bh.Gains;
                for (int j = 0; j < N; j++)
                {
                    gains.MoveNext();
                    double g = gains.Current;
                    _data[j].mul(g);
                    _data[fftSize - j - 1].mul(g);
                }

                _gotdata = true;
            }

            ComplexBufferReader cbr = new ComplexBufferReader(_data, 0, N);

            //bh.Input = cbr;

            return(cbr);
        }