Esempio n. 1
0
    /// <summary>
    /// Create Frequency Table
    /// </summary>
    /// <param name="basefreq">Minimum frequency in Hertz</param>
    /// <param name="bands">Number of frequency bands</param>
    /// <param name="bandsperoctave">Frequency resolution in Bands Per Octave</param>
    /// <returns>Frequency Array</returns>
    public static double[] FrequencyArray(double basefreq, int bands, double bandsperoctave)
    {
        int i = 0;

        double[] freq = new double[bands];
        double   maxfreq;

        if (LOGBASE == 1.0)
        {
            maxfreq = bandsperoctave;             // in linear mode we use bpo to store the maxfreq since we couldn't deduce maxfreq otherwise
        }
        else
        {
            maxfreq = basefreq * Math.Pow(LOGBASE, ((double)(bands - 1) / bandsperoctave));
        }

        for (i = 0; i < bands; i++)
        {
            freq[i] = GlobalMembersDsp.LogPositionToFrequency((double)i / (double)(bands - 1), basefreq, maxfreq);          //band's central freq
        }

        if (GlobalMembersDsp.LogPositionToFrequency((double)bands / (double)(bands - 1), basefreq, maxfreq) > 0.5)
        {
            // TODO change sampling rate instead
            Console.Write("Warning: Upper frequency limit above Nyquist frequency\n");
        }

        return(freq);
    }
Esempio n. 2
0
    /// <summary>
    /// Noise synthesis mode
    /// </summary>
    /// <param name="d">Image</param>
    /// <param name="Xsize">Specifies the desired width of the spectrogram</param>
    /// <param name="bands">Specifies the desired height of the spectrogram (bands)</param>
    /// <param name="samplecount">Number of samples</param>
    /// <param name="samplerate">Sample rate</param>
    /// <param name="basefreq">Base frequency in Hertz</param>
    /// <param name="pixpersec">Time resolution in Pixels Per Second</param>
    /// <param name="bpo">Frequency resolution in Bands Per Octave</param>
    /// <returns></returns>
    public static double[] SynthesizeNoise(ref double[][] d, ref int Xsize, ref int bands, ref int samplecount, ref int samplerate, ref double basefreq, ref double pixpersec, ref double bpo)
    {
        double[] s;                                                             // final signal
        double   coef;

        double[] noise;                                 // filtered looped noise
        double   loop_size_sec = LOOP_SIZE_SEC;         // size of the filter bank loop, in seconds. Later to be taken from user input
        int      loop_size     = 0;                     // size of the filter bank loop, in samples. Deduced from loop_size_sec
        int      loop_size_min = 0;                     // minimum required size for the filter bank loop, in samples. Calculated from the longest windowed sinc's length

        double[] pink_noise;                            // original pink noise (in the frequency domain)
        double   mag;                                   // parameters for the creation of pink_noise's samples
        double   phase;

        double[] envelope; // interpolated envelope
        double[] lut;      // Blackman Sqaure look-up table
        double[] freq;     // frequency look-up table
        double   maxfreq;  // central frequency of the last band

        int i  = 0;        // general purpose iterator
        int ib = 0;        // bands iterator
        int il = 0;        // loop iterator

        int Fa = 0;        // Fa is the index of the band's start in the frequency domain
        int Fd = 0;        // Fd is the index of the band's end in the frequency domain

        double La;         // La is the log2 of the frequency of Fa
        double Ld;         // Ld is the log2 of the frequency of Fd
        double Li;         // Li is the iterative frequency between La and Ld defined logarithmically

        freq = GlobalMembersDsp.FrequencyArray(basefreq, bands, bpo);

        if (LOGBASE == 1.0)
        {
            maxfreq = bpo;             // in linear mode we use bpo to store the maxfreq since we couldn't deduce maxfreq otherwise
        }
        else
        {
            maxfreq = basefreq * Math.Pow(LOGBASE, ((double)(bands - 1) / bpo));
        }

        clockA = GlobalMembersUtil.GetTime();

        samplecount = (int)GlobalMembersUtil.RoundOff(Xsize / pixpersec);        // calculation of the length of the final signal
        Console.Write("Sound duration : {0:f3} s\n", (double)samplecount / samplerate);

        // allocation of the final signal
        s = new double[samplecount];

        // allocation of the interpolated envelope
        envelope = new double[samplecount];

        //********Loop size calculation********
        loop_size = (int)loop_size_sec * samplerate;

        if (LOGBASE == 1.0)
        {
            loop_size_min = (int)GlobalMembersUtil.RoundOff(4.0 * 5.0 / freq[1] - freq[0]);          // linear mode
        }
        else
        {
            loop_size_min = (int)GlobalMembersUtil.RoundOff(2.0 * 5.0 / ((freq[0] * Math.Pow(2.0, -1.0 / (bpo))) * (1.0 - Math.Pow(2.0, -1.0 / bpo))));         // this is the estimate of how many samples the longest FIR will take up in the time domain
        }
        if (loop_size_min > loop_size)
        {
            loop_size = loop_size_min;
        }

        loop_size = GlobalMembersUtil.NextPrime(loop_size);         // enlarge the loop_size to the next multiple of short primes in order to make IFFTs faster
        //--------Loop size calculation--------

        //********Pink noise generation********
        pink_noise = new double[loop_size];

        for (i = 1; i < (loop_size + 1) >> 1; i++)
        {
            mag   = Math.Pow((double)i, 0.5 - 0.5 * LOGBASE);  // FIXME something's not necessarily right with that formula
            phase = GlobalMembersUtil.DoubleRandom() * PI;     // random phase between -pi and +pi

            pink_noise[i]             = mag * Math.Cos(phase); // real part
            pink_noise[loop_size - i] = mag * Math.Sin(phase); // imaginary part
        }
        //--------Pink noise generation--------

        // allocate noise
        noise = new double[loop_size];

        lut = GlobalMembersDsp.BlackmanSquareLookupTable(ref BMSQ_LUT_SIZE);         // Blackman Square look-up table initalisation

        for (ib = 0; ib < bands; ib++)
        {
            Console.Write("{0,4:D}/{1:D}\r", ib + 1, bands);

            // reset filtered noise
            for (i = 0; i < loop_size; i++)
            {
                noise[i] = 0;                                     // reset sband
            }
            //********Filtering********
            Fa = (int)GlobalMembersUtil.RoundOff(GlobalMembersDsp.LogPositionToFrequency((double)(ib - 1) / (double)(bands - 1), basefreq, maxfreq) * loop_size);
            Fd = (int)GlobalMembersUtil.RoundOff(GlobalMembersDsp.LogPositionToFrequency((double)(ib + 1) / (double)(bands - 1), basefreq, maxfreq) * loop_size);
            La = GlobalMembersDsp.FrequencyToLogPosition((double)Fa / (double)loop_size, basefreq, maxfreq);
            Ld = GlobalMembersDsp.FrequencyToLogPosition((double)Fd / (double)loop_size, basefreq, maxfreq);

            if (Fd > loop_size / 2)
            {
                Fd = loop_size / 2;               // stop reading if reaching the Nyquist frequency
            }
            if (Fa < 1)
            {
                Fa = 1;
            }

            Console.Write("{0,4:D}/{1:D}   {2:f2} Hz - {3:f2} Hz\r", ib + 1, bands, (double)Fa * samplerate / loop_size, (double)Fd * samplerate / loop_size);

            for (i = Fa; i < Fd; i++)
            {
                Li                       = GlobalMembersDsp.FrequencyToLogPosition((double)i / (double)loop_size, basefreq, maxfreq); // calculation of the logarithmic position
                Li                       = (Li - La) / (Ld - La);
                coef                     = 0.5 - 0.5 * Math.Cos(2.0 * PI * Li);                                                       // Hann function
                noise[i + 1]             = pink_noise[i + 1] * coef;
                noise[loop_size - 1 - i] = pink_noise[loop_size - 1 - i] * coef;
            }
            //--------Filtering--------

            GlobalMembersDsp.FFT(ref noise, ref noise, loop_size, FFTMethod.IDFT);             // IFFT of the filtered noise

            // blank the envelope
            for (i = 0; i < samplecount; i++)
            {
                envelope[i] = 0;                                                                                                                   // reset sband
            }
            GlobalMembersDsp.BlackmanSquareInterpolation(ref d[bands - ib - 1], ref envelope, ref Xsize, ref samplecount, ref lut, BMSQ_LUT_SIZE); // interpolation of the envelope

            il = 0;
            for (i = 0; i < samplecount; i++)
            {
                s[i] += envelope[i] * noise[il]; // modulation
                il++;                            // increment loop iterator
                if (il == loop_size)             // if the array iterator has reached the end of the array, it's reset
                {
                    il = 0;
                }
            }
        }

        Console.Write("\n");

        GlobalMembersDsp.Normalize(ref s, ref samplecount, 1.0);

        return(s);
    }
Esempio n. 3
0
    /// <summary>
    /// Analyze the input
    /// </summary>
    /// <param name="s">Sound (original signal)</param>
    /// <param name="samplecount">Sample count (samplecount is the original signal's orginal length)</param>
    /// <param name="samplerate">Sample rate</param>
    /// <param name="Xsize">Specifies the desired width of the spectrogram</param>
    /// <param name="bands">Specifies the desired height of the spectrogram (bands is the total count of bands)</param>
    /// <param name="bpo">Frequency resolution in Bands Per Octave</param>
    /// <param name="pixpersec">Time resolution in Pixels Per Second</param>
    /// <param name="basefreq">Minimum frequency in Hertz</param>
    /// <returns>Image</returns>
    public static double[][] Analyze(ref double[] s, ref int samplecount, ref int samplerate, ref int Xsize, ref int bands, ref double bpo, ref double pixpersec, ref double basefreq)
    {
        int i  = 0;                     // i is a general purpose iterator
        int ib = 0;                     // ib is the band iterator
        int Mb = 0;                     // Mb is the length of the original signal once zero-padded (always even)
        int Mc = 0;                     // Mc is the length of the filtered signal
        int Md = 0;                     // Md is the length of the envelopes once downsampled (constant)
        int Fa = 0;                     // Fa is the index of the band's start in the frequency domain
        int Fd = 0;                     // Fd is the index of the band's end in the frequency domain

        double[][] @out;                // @out is the output image
        double[]   h;
        double[]   freq;                // freq is the band's central frequency
        double[]   t;                   // t is temporary pointer to a new version of the signal being worked on
        double     coef;                // coef is a temporary modulation coefficient
        double     La;                  // La is the log2 of the frequency of Fa
        double     Ld;                  // Ld is the log2 of the frequency of Fd
        double     Li;                  // Li is the iterative frequency between La and Ld defined logarithmically
        double     maxfreq;             // maxfreq is the central frequency of the last band

        freq = GlobalMembersDsp.FrequencyArray(basefreq, bands, bpo);

        if (LOGBASE == 1.0)
        {
            maxfreq = bpo;             // in linear mode we use bpo to store the maxfreq since we couldn't deduce maxfreq otherwise
        }
        else
        {
            maxfreq = basefreq * Math.Pow(LOGBASE, ((double)(bands - 1) / bpo));
        }

        Xsize = (int)(samplecount * pixpersec);

        if (GlobalMembersUtil.FMod((double)samplecount * pixpersec, 1.0) != 0.0)
        {
            // round-up
            Xsize++;
        }
        Console.Write("Image size : {0:D}x{1:D}\n", Xsize, bands);

        @out = new double[bands][];

        clockA = GlobalMembersUtil.GetTime();

        //********ZEROPADDING********	Note : Don't do it in Circular mode
        // Mb is the length of the original signal once zero-padded (always even)
        if (LOGBASE == 1.0)
        {
            Mb = samplecount - 1 + (int)GlobalMembersUtil.RoundOff(5.0 / freq[1] - freq[0]);           // linear mode
        }
        else
        {
            Mb = samplecount - 1 + (int)GlobalMembersUtil.RoundOff(2.0 * 5.0 / ((freq[0] * Math.Pow(LOGBASE, -1.0 / (bpo))) * (1.0 - Math.Pow(LOGBASE, -1.0 / bpo))));
        }

        if (Mb % 2 == 1)      // if Mb is odd
        {
            Mb++;             // make it even (for the sake of simplicity)
        }

        Mc = 0;
        Md = 0;

        Mb = (int)GlobalMembersUtil.RoundOff((double)GlobalMembersUtil.NextPrime((int)GlobalMembersUtil.RoundOff(Mb * pixpersec)) / pixpersec);

        // Md is the length of the envelopes once downsampled (constant)
        Md = (int)GlobalMembersUtil.RoundOff(Mb * pixpersec);

        // realloc to the zeropadded size
        Array.Resize <double>(ref s, Mb);

        // zero-out the padded area. Equivalent of : for (i=samplecount; i<Mb; i++) s[i] = 0;
        for (i = samplecount; i < Mb; i++)
        {
            s[i] = 0;
        }
        //--------ZEROPADDING--------

        //Export.exportCSV(String.Format("samples_before_fft.csv"), s, 256);
        GlobalMembersDsp.FFT(ref s, ref s, Mb, FFTMethod.DFT);         // In-place FFT of the original zero-padded signal
        //Export.exportCSV(String.Format("samples_after_fft.csv"), s, 256);

        for (ib = 0; ib < bands; ib++)
        {
            //********Filtering********
            Fa = (int)GlobalMembersUtil.RoundOff(GlobalMembersDsp.LogPositionToFrequency((double)(ib - 1) / (double)(bands - 1), basefreq, maxfreq) * Mb);
            Fd = (int)GlobalMembersUtil.RoundOff(GlobalMembersDsp.LogPositionToFrequency((double)(ib + 1) / (double)(bands - 1), basefreq, maxfreq) * Mb);
            La = GlobalMembersDsp.FrequencyToLogPosition((double)Fa / (double)Mb, basefreq, maxfreq);
            Ld = GlobalMembersDsp.FrequencyToLogPosition((double)Fd / (double)Mb, basefreq, maxfreq);

            if (Fd > Mb / 2)
            {
                Fd = Mb / 2;               // stop reading if reaching the Nyquist frequency
            }
            if (Fa < 1)
            {
                Fa = 1;
            }

            // Mc is the length of the filtered signal
            Mc = (Fd - Fa) * 2 + 1;
            // '*2' because the filtering is on both real and imaginary parts,
            // '+1' for the DC.
            // No Nyquist component since the signal length is necessarily odd

            if (Md > Mc)               // if the band is going to be too narrow
            {
                Mc = Md;
            }

            if (Md < Mc)               // round the larger bands up to the next integer made of 2^n * 3^m
            {
                Mc = GlobalMembersUtil.NextPrime(Mc);
            }

            Console.Write("{0,4:D}/{1:D} (FFT size: {2,6:D})   {3:f2} Hz - {4:f2} Hz\r", ib + 1, bands, Mc, (double)Fa * samplerate / Mb, (double)Fd * samplerate / Mb);

            @out[bands - ib - 1] = new double[Mc + 1];

            for (i = 0; i < Fd - Fa; i++)
            {
                Li   = GlobalMembersDsp.FrequencyToLogPosition((double)(i + Fa) / (double)Mb, basefreq, maxfreq); // calculation of the logarithmic position
                Li   = (Li - La) / (Ld - La);
                coef = 0.5 - 0.5 * Math.Cos(2.0 * PI * Li);                                                       // Hann function

                @out[bands - ib - 1][i + 1]      = s[i + 1 + Fa] * coef;
                @out[bands - ib - 1][Mc - 1 - i] = s[Mb - Fa - 1 - i] * coef;
            }
            //--------Filtering--------
            //Export.exportCSV(String.Format("test/band_{0}_filtered.csv", bands-ib-1), @out[bands-ib-1]);

            //********90° rotation********
            h = new double[Mc + 1];

            // Rotation : Re' = Im; Im' = -Re
            for (i = 0; i < Fd - Fa; i++)
            {
                h[i + 1]      = @out[bands - ib - 1][Mc - 1 - i];           // Re' = Im
                h[Mc - 1 - i] = -@out[bands - ib - 1][i + 1];               // Im' = -Re
            }
            //--------90° rotation--------

            //********Envelope detection********
            //Export.exportCSV(String.Format("test/band_{0}_rotated.csv", bands-ib-1), @out[bands-ib-1]);

            GlobalMembersDsp.FFT(ref @out[bands - ib - 1], ref @out[bands - ib - 1], Mc, FFTMethod.IDFT);       // In-place IFFT of the filtered band signal
            GlobalMembersDsp.FFT(ref h, ref h, Mc, FFTMethod.IDFT);                                             // In-place IFFT of the filtered band signal rotated by 90°

            //Export.exportCSV(String.Format("test/band_{0}_before.csv", bands-ib-1), @out[bands-ib-1]);

            for (i = 0; i < Mc; i++)
            {
                // TODO: why does the above crash?!
                //for (i = 0; i < @out[bands-ib-1].Length; i++) {
                // Magnitude of the analytic signal
                double x        = @out[bands - ib - 1][i];
                double y        = h[i];
                double xSquared = x * x;
                double ySquared = y * y;
                double mag      = Math.Sqrt(xSquared + ySquared);
                @out[bands - ib - 1][i] = mag;
            }

            Array.Clear(h, 0, h.Length);
            //--------Envelope detection--------

            //********Downsampling********
            if (Mc < Md)                                             // if the band doesn't have to be resampled
            {
                Array.Resize <double>(ref @out[bands - ib - 1], Md); // simply ignore the end of it
            }

            if (Mc > Md)               // If the band *has* to be downsampled
            {
                t = @out[bands - ib - 1];
                @out[bands - ib - 1] = GlobalMembersDsp.BlackmanDownsampling(@out[bands - ib - 1], Mc, Md);         // Blackman downsampling

                Array.Clear(t, 0, t.Length);
            }
            //--------Downsampling--------

            Array.Resize <double>(ref @out[bands - ib - 1], Xsize);        // Tail chopping

            //Export.exportCSV(String.Format("test/band_{0}_after.csv", bands-ib-1), @out[bands-ib-1]);
        }

        Console.Write("\n");

        GlobalMembersDsp.Normalize(ref @out, ref Xsize, ref bands, 1.0);

        //Export.exportCSV(String.Format("out.csv"), @out);
        return(@out);
    }