PadToPowerOfTwo() public method

public PadToPowerOfTwo ( ) : void
return void
Ejemplo n.º 1
0
        public static FilterProfile Profile(ISoundObj impulse, SmoothingType type, double resolution)
        {
            uint nSR  = impulse.SampleRate;
            uint nSR2 = nSR / 2;

            ushort nChannels = impulse.NumChannels;

            for (ushort c = 0; c < nChannels; c++)
            {
                // Read channel into a buffer
                SingleChannel channel = impulse.Channel(c);
                SoundBuffer   buff    = new SoundBuffer(channel);
                buff.ReadAll();

                // And then double in length to prevent wraparound
                buff.PadTo(buff.Count * 2);
                // Pad to next higher power of two
                buff.PadToPowerOfTwo();
                // Read out into array of complex
                Complex[][] data  = buff.ToComplexArray();
                Complex[]   cdata = data[0];

                // Then we're done with the buffer for this channel
                buff = null;
                GC.Collect();

                // FFT in place
                Fourier.FFT(cdata.Length, cdata);

                int n = cdata.Length / 2;

                // Now we have an array of complex, from 0Hz to Nyquist and back again.
                // We really only care about the first half of the cdata buffer, but
                // treat it as circular anyway (i.e. wrap around for negative values).
                //
                // We're only working with magnitudes from here on,
                // so we can save some space by computing mags right away and storing them in the
                // real part of the complex array; then we can use the imaginary portion for the
                // smoothed data.
                for (int j = 0; j < cdata.Length; j++)
                {
                    cdata[j].Re = cdata[j].Magnitude;
                    cdata[j].Im = 0;
                }

                // Take a rectangular window of width (resolution)*(octave or ERB band)
                // Add up all magnitudes falling within this window
                //
                // Move the window forward by one thingummajig
                //double wMid = 0;    // center of the window
                //double wLen = 0;
            }
            return(new FilterProfile()); // temp
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Calculate the weighted volume of a *single channel* sound source.
        /// NB: this consumes lots of memory for long sources.
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dbSPL"></param>
        /// <returns>Volume (units, not dB)</returns>
        public static double WeightedVolume1(ISoundObj src, double dbSPL, double dbSPLBase)
        {
            if (src.NumChannels != 1)
            {
                throw new ArgumentException("Requires single-channel");
            }

            // Read channel into a buffer
            SoundBuffer buff = new SoundBuffer(src);

            buff.ReadAll();

            // And then double in length to prevent wraparound
            buff.PadTo(buff.Count * 2);
            // Pad to next higher power of two
            buff.PadToPowerOfTwo();
            int n = buff.Count;

            double wvImpulse = WeightedVolume2(buff, dbSPL, dbSPLBase);

            // compare with a Dirac pulse the same length
            CallbackSource dirac = new CallbackSource(1, src.SampleRate, delegate(long j)
            {
                if (j >= n)
                {
                    return(null);
                }
                double v = 0;
                if (j == n / 2)
                {
                    v = 1;
                }
                return(new Sample(v));
            });

            buff = new SoundBuffer(dirac);
            buff.ReadAll();
            double wvDirac = WeightedVolume2(buff, dbSPL, dbSPLBase);

            buff = null;
            GC.Collect();

            return(wvImpulse / wvDirac);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Calculate the weighted volume of a *single channel* sound source.
        /// NB: this consumes lots of memory for long sources.
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dbSPL"></param>
        /// <returns>Volume (units, not dB)</returns>
        public static double WeightedVolume1(ISoundObj src, double dbSPL, double dbSPLBase)
        {
            if (src.NumChannels != 1)
            {
                throw new ArgumentException("Requires single-channel");
            }

            // Read channel into a buffer
            SoundBuffer buff = new SoundBuffer(src);
            buff.ReadAll();

            // And then double in length to prevent wraparound
            buff.PadTo(buff.Count * 2);
            // Pad to next higher power of two
            buff.PadToPowerOfTwo();
            int n = buff.Count;

            double wvImpulse = WeightedVolume2(buff, dbSPL, dbSPLBase);

            // compare with a Dirac pulse the same length
            CallbackSource dirac = new CallbackSource(1, src.SampleRate, delegate(long j)
            {
                if (j >= n)
                {
                    return null;
                }
                double v = 0;
                if (j == n / 2)
                {
                    v = 1;
                }
                return new Sample(v);
            });
            buff = new SoundBuffer(dirac);
            buff.ReadAll();
            double wvDirac = WeightedVolume2(buff, dbSPL, dbSPLBase);

            buff = null;
            GC.Collect();

            return wvImpulse / wvDirac;
        }
Ejemplo n.º 4
0
        public static FilterProfile Profile(ISoundObj impulse, SmoothingType type, double resolution)
        {
            uint nSR = impulse.SampleRate;
            uint nSR2 = nSR / 2;

            ushort nChannels = impulse.NumChannels;
            for (ushort c = 0; c < nChannels; c++)
            {
                // Read channel into a buffer
                SingleChannel channel = impulse.Channel(c);
                SoundBuffer buff = new SoundBuffer(channel);
                buff.ReadAll();

                // And then double in length to prevent wraparound
                buff.PadTo(buff.Count * 2);
                // Pad to next higher power of two
                buff.PadToPowerOfTwo();
                // Read out into array of complex
                Complex[][] data = buff.ToComplexArray();
                Complex[] cdata = data[0];

                // Then we're done with the buffer for this channel
                buff = null;
                GC.Collect();

                // FFT in place
                Fourier.FFT(cdata.Length, cdata);

                int n = cdata.Length / 2;

                // Now we have an array of complex, from 0Hz to Nyquist and back again.
                // We really only care about the first half of the cdata buffer, but
                // treat it as circular anyway (i.e. wrap around for negative values).
                //
                // We're only working with magnitudes from here on,
                // so we can save some space by computing mags right away and storing them in the
                // real part of the complex array; then we can use the imaginary portion for the
                // smoothed data.
                for (int j = 0; j < cdata.Length; j++)
                {
                    cdata[j].Re = cdata[j].Magnitude;
                    cdata[j].Im = 0;
                }

                // Take a rectangular window of width (resolution)*(octave or ERB band)
                // Add up all magnitudes falling within this window
                //
                // Move the window forward by one thingummajig
                //double wMid = 0;    // center of the window
                //double wLen = 0;
            }
            return new FilterProfile(); // temp
        }
Ejemplo n.º 5
0
        static SoundObj Deconvolve(string infile, out Complex[] impulseFFT, out int peakpos)
        {
            WaveReader reader = new WaveReader(infile);
            ushort nChannels = reader.NumChannels;
            uint sampleRate = reader.SampleRate;

            CallbackSource cs;
            SingleChannel[] channels = new SingleChannel[2];
            Complex[][][] data = new Complex[2][][];
            double[] stdDev = new double[2];
            double[] maxLogs = new double[2];
            double[] maxs = new double[2];
            double[] avgLog = new double[2];

            Complex[] swp_data = null;
            Complex[] mea_data = null;

            if (_fmax == int.MaxValue)
            {
                _fmax = (int)sampleRate / 2;
            }
            bool isEstimatedSweepRange = false;

            if (nChannels != 2)
            {
                throw new Exception("Input must have two channels.");
            }

            peakpos = 0;
            int cSwp = 0;
            int cMea = 1;
            int L = 0;
            int Nh = 0;
            double mx;

            double max = 0;
            double maxLog = 0;
            double stdev = 0;
            double avg = 0;

            for (int iteration = 1; iteration <= 2; iteration++)
            {
                // Read and FFT all the data
                // one channel at a time
                for (ushort c = 0; c < 2; c++)
                {
                    SingleChannel channel = reader.Channel(c);
                    Complex[] cdata;

                    SoundBuffer buff = new SoundBuffer(channel);
                    buff.ReadAll();

                    if (iteration==2 && _split)
                    {
                        // Split up the input file
                        string infile2 = Path.ChangeExtension(Path.GetFileName(infile), ".PCM");
                        if (c == cSwp)
                        {
                            WaveWriter wri = new WaveWriter("refchannel_" + infile2, 1, channel.SampleRate, 32, DitherType.NONE, WaveFormat.IEEE_FLOAT);
                            wri.Input = buff;
                            wri.Run(); wri.Close();
                        }
                        if (c == cMea)
                        {
                            WaveWriter wri = new WaveWriter("sweep_" + infile2, 1, channel.SampleRate, 32, DitherType.NONE, WaveFormat.IEEE_FLOAT);
                            wri.Input = buff;
                            wri.Run(); wri.Close();
                        }
                    }

                    // And then double in length to prevent wraparound
                    buff.PadTo(buff.Count * 2);

                    // Pad to next higher power of two
                    buff.PadToPowerOfTwo();

                    // Read out into array of complex
                    data[c] = buff.ToComplexArray();

                    // Then we're done with the buffer for this channel
                    buff = null;
                    GC.Collect();

                    cdata = data[c][0];

                    if (iteration==2 && c==cSwp && _power > 0)
                    {
                        // Deconvolve against a power of the sweep,
                        // for distortion measurement of harmonic _power
                        Complex p = new Complex((double)_power,0);
                        for (int j = 0; j < cdata.Length; j++)
                        {
                            cdata[j].Pow(p);
                        }
                    }

                    // FFT in place
                    Fourier.FFT(cdata.Length, cdata);

                    if (false && iteration==1)
                    {
                        // write the fft magnitudes to disk
                        cs = new CallbackSource(1, sampleRate, delegate(long j)
                        {
                            if (j >= cdata.Length)
                            {
                                return null;
                            }
                            Complex si = cdata[j];
                            Sample s = new Sample(1);
                            double f = (double)j * sampleRate / cdata.Length;
                            s[0] = mag(sampleRate, f, si.Magnitude);
                            return s;
                        });
                        // cs.SampleRate = sampleRate;
                        // cs.NumChannels = 1;
                        WaveWriter writer = new WaveWriter("fft_" + c + "_" + infile);
                        writer.Format = WaveFormat.IEEE_FLOAT;
                        writer.BitsPerSample = 32;
                        writer.SampleRate = _sampleRate;
                        writer.Input = cs;
                        writer.Normalization = -3;
                        writer.Run();
                        writer.Close();
                    }

                    // Take a slice of the FFT, std dev of log(|fft|),
                    // the lower value should be the sweep
                    int n3 = cdata.Length / 4;
                    int n1 = n3 / 2;
                    int n2 = n1 + n3;
                    get_stddev(sampleRate, n1, n2, cdata, out max, out maxLog, out stdev, out avg);

                    maxs[c] = max;
                    maxLogs[c] = maxLog;
                    stdDev[c] = stdev;
                    avgLog[c] = avg;

                    // Trace.WriteLine("Channel {0} standard deviation {1}", c, stdDev[c]);
                }
                GC.Collect();

                if (iteration == 1)
                {
                    if (stdDev[1] < stdDev[0])
                    {
                        if (_refchannel == -1)
                        {
                            cSwp = 1;
                            cMea = 0;
                            stderr.WriteLine("  Right channel seems to be the sweep");
                        }
                        else
                        {
                            stderr.WriteLine("  Right channel seems to be the sweep");
                            stderr.WriteLine("  But you said use refchannel {0}, so using that.", _refchannel);
                            cSwp = _refchannel;
                            cMea = (_nInFiles - 1) - _refchannel;
                        }
                    }
                    else
                    {
                        if (_refchannel == -1)
                        {
                            stderr.WriteLine("  Left channel seems to be the sweep");
                        }
                        else
                        {
                            stderr.WriteLine("  Left channel seems to be the sweep");
                            stderr.WriteLine("  But you said use refchannel {0}, so using that.", _refchannel);
                            cSwp = _refchannel;
                            cMea = (_nInFiles - 1) - _refchannel;
                        }
                    }
                }

                swp_data = data[cSwp][0];
                mea_data = data[cMea][0];

                L = swp_data.Length;
                Nh = L / 2;

                // stderr.WriteLine("avgLog=" + avgLog[cSwp] + " maxLog=" + maxLogs[cSwp]);

                double hz1 = L / sampleRate;
                if (false && _fmin == 0)
                {
                    isEstimatedSweepRange = true;
                    // Working back from 100Hz,
                    // Look for the first range where average of a 1Hz window
                    // is less than 0.7* average for the sweep itself
                    int kmin = (int)(hz1 * 100);
                    _fmin = 100;
                    while (kmin > 0)
                    {
                        get_stddev(sampleRate, kmin, (int)(kmin + hz1), swp_data, out max, out maxLog, out stdev, out avg);
                        if (avg < avgLog[cSwp] * 0.5)
                        {
                            break;
                        }
                        kmin -= (int)hz1;
                        _fmin--;
                    }
                    // stderr.WriteLine("avg/2: kmin=" + kmin + ", _fmin=" + _fmin);
                }

                if (false && _fmax == sampleRate / 2)
                {
                    isEstimatedSweepRange = true;
                    // Working forward from (say) 15kHz,
                    // Look for the first range where average of a 100Hz window
                    // is less than 0.7* average for the sweep itself
                    int kmax = (int)(hz1 * 10000);
                    _fmax = 10000;
                    get_stddev(sampleRate, kmax, (int)(kmax + 100 * hz1), swp_data, out max, out maxLog, out stdev, out avg);
                    double stdTest = stdev;
                    while (kmax < L / 2)
                    {
                        get_stddev(sampleRate, kmax, (int)(kmax + 100 * hz1), swp_data, out max, out maxLog, out stdev, out avg);
                        if (avg < avgLog[cSwp] * 0.5)
                        {
                            break;
                        }
                        kmax += (int)(100 * hz1);
                        _fmax += 100;
                    }
                    // stderr.WriteLine("StdDev Peak: kmax=" + kmax + ", _fmax=" + _fmax + ", sdev=" + stdev + " ref " + stdTest + " (1Hz=" + hz1 + "), avgLog=" + avg);
                }

                if (!_noSubsonicFilter)
                {
                    // Filter LF from the measurement data
                    // to avoid spurious stuff below 15Hz
                    int s1 = (int)(7 * hz1);
                    int s2 = (int)(15 * hz1);
                    for (int j = 0; j < s1; j++)
                    {
                        mea_data[j].Set(0, 0);
                        mea_data[swp_data.Length - j - 1].Set(0, 0);
                    }
                    for (int j = s1; j < s2; j++)
                    {
                        double n = (double)(j - s1) / (s2 - s1);
                        double m = 0.5 * (1 + Math.Cos(Math.PI * (1 + n)));
                        mea_data[j].mul(m);
                        mea_data[swp_data.Length - j - 1].mul(m);
                    }
                }

                // Divide in complex domain
                for (int j = 0; j < swp_data.Length; j++)
                {
                    swp_data[j].idiv(mea_data[j]);
                    // Make a copy in mea_data, we'll need it later
                    mea_data[j] = swp_data[j];
                }

                // IFFT to get the impulse response
                Fourier.IFFT(swp_data.Length, swp_data);

                // Scan the imp to find maximum
                mx = 0;
                int mp = 0;
                for (int j = 0; j < sampleRate; j++)
                {
                    Complex si = swp_data[j];
                    double mg = Math.Abs(si.Magnitude);
                    if (mg > mx) { mx = mg; mp = j; }
                }
                // Look one sample backwards from max position
                // to find the likely "pulse peak" if within 30% of max
                peakpos = mp;
                if (mp>0 && swp_data[mp - 1].Magnitude / mx > 0.7)
                {
                    peakpos = mp - 1;
                }
            }

            // stderr.WriteLine("  {0} range {1}Hz to {2}Hz", isEstimatedSweepRange ? "Estimated sweep" : "Sweep", _fmin, _fmax);
            if (_fmaxSpecified && _fminSpecified)
            {
                HackSweep(swp_data, mea_data, peakpos, L, sampleRate);
            }
            else
            {
                Fourier.FFT(swp_data.Length, swp_data);
            }

            // Window the extremities of the whole response, finally?

            if (true)
            {
                // Make a copy in mea_data, we'll need it later
                for (int j = 0; j < swp_data.Length; j++)
                {
                    mea_data[j] = swp_data[j];
                }

                // Return FFT of impulse
                impulseFFT = mea_data;
            }

            // IFFT to get the impulse response
            Fourier.IFFT(swp_data.Length, swp_data);

            // Scan the imp to find maximum
            mx = 0;
            for (int j = 0; j < sampleRate; j++)
            {
                Complex si = swp_data[j];
                double mg = Math.Abs(si.Magnitude);
                if (mg > mx) mx = mg;
            }

            if (_noNorm)
            {
                mx = 1.0;
            }

            // Yield the first half (normalized) as result
            cs = new CallbackSource(1, sampleRate, delegate(long j)
            {
                if (j > (_returnAll ? L-1 : L / 2))
                {
                    return null;
                }
                Complex si = swp_data[j];
                Sample s = new Sample(si.Re / mx);
                return s;
            });
            cs.SampleRate = sampleRate;
            cs.NumChannels = 1;

            return cs;
        }
Ejemplo n.º 6
0
        private static double[] magbands(ISoundObj impulse, double bins)
        {
            uint nSR  = impulse.SampleRate;
            uint nSR2 = nSR / 2;

            int nn = (int)bins + 1;

            double[] muff = new double[nn];

            ushort nChannels = impulse.NumChannels;

            for (ushort c = 0; c < nChannels; c++)
            {
                // Read channel into a buffer
                SingleChannel channel = impulse.Channel(c);
                SoundBuffer   buff    = new SoundBuffer(channel);
                buff.ReadAll();

                // And then double in length to prevent wraparound
                buff.PadTo(buff.Count * 2);
                // Pad to next higher power of two
                buff.PadToPowerOfTwo();
                // Read out into array of complex
                Complex[][] data  = buff.ToComplexArray();
                Complex[]   cdata = data[0];

                // Then we're done with the buffer for this channel
                buff = null;
                GC.Collect();

                // FFT in place
                Fourier.FFT(cdata.Length, cdata);

                int n = cdata.Length / 2;

                // Drop the FFT magnitudes into the 'muff' array
                // according to an ERB-based scale (near-logarithmic).
                // Then smoothing is easy.
                double binw    = (nSR2 / (double)n);
                int    prevbin = 0;
                int    nbin    = 0;
                double v       = 0;
                for (int j = 0; j < n; j++)
                {
                    double f   = (double)j * binw;             // equiv freq, Hz
                    int    bin = (int)ERB.f2bin(f, nSR, bins); // the bin we drop this sample in
                    v += cdata[j].Magnitude;
                    nbin++;

                    if ((bin > prevbin) || (j == n - 1))
                    {
                        muff[prevbin] += (v / nbin);
                        v              = 0;
                        nbin           = 0;
                        prevbin        = bin;
                    }
                }
            }

            // Now muff is sum(all channels) of average-magnitude-per-bin.
            // Divide it all by the number of channels, so our gains are averaged...
            for (int j = 0; j < muff.Length; j++)
            {
                muff[j] = muff[j] / nChannels;
            }

            return(muff);
        }