public static void Write8Bit(BinaryFile wavfile, double[][] sound, int samplecount, int channels)
    {
        int    i  = 0;
        int    ic = 0;
        double val;
        byte   @byte = new byte();

                #if DEBUG
        Console.Write("Write8Bit...\n");
                #endif

        for (i = 0; i < samplecount; i++)
        {
            for (ic = 0; ic < channels; ic++)
            {
                val = GlobalMembersUtil.RoundOff((sound[ic][i] + 1.0) * 128.0);

                if (val > 255)
                {
                    val = 255;
                }
                if (val < 0)
                {
                    val = 0;
                }

                @byte = (byte)val;

                wavfile.Write(@byte);
            }
        }
    }
Exemple #2
0
    /// <summary>
    /// Windowd Sinc method
    /// </summary>
    /// <param name="length">Length</param>
    /// <param name="bw">Bandwidth</param>
    /// <returns></returns>
    public static double[] WindowedSinc_max(int length, double bw)
    {
        // http://www.dspguide.com/ch16/1.htm

        int    i   = 0;
        int    bwl = 0;   // integer transition bandwidth
        double tbw;       // double transition bandwidth

        double[] h;       // kernel
        double   x;       // position in the antiderivate of the Blackman function of the sample we're at
        double   coef;    // coefficient obtained from the function

        tbw = bw * (double)(length - 1);
        bwl = GlobalMembersUtil.RoundUp(tbw);

        h = new double[length];

        for (i = 1; i < length; i++)
        {
            h[i] = 1.0;
        }

        for (i = 0; i < bwl; i++)
        {
            x = (double)i / tbw;              // position calculation between 0.0 and 1.0
            // antiderivative of the Blackman window function
            coef              = 0.42 * x - (0.5 / (2.0 * PI)) * Math.Sin(2.0 * PI * x) + (0.08 / (4.0 * PI)) * Math.Sin(4.0 * PI * x);
            coef             *= 1.0 / 0.42;
            h[i + 1]          = coef;
            h[length - 1 - i] = coef;
        }

        return(h);
    }
    public static void Write32Bit(BinaryFile wavfile, double[][] sound, int samplecount, int channels)
    {
        int    i  = 0;
        int    ic = 0;
        double val;

                #if DEBUG
        Console.Write("Write32Bit...\n");
                #endif

        for (i = 0; i < samplecount; i++)
        {
            for (ic = 0; ic < channels; ic++)
            {
                val = GlobalMembersUtil.RoundOff(sound[ic][i] * 2147483648.0);

                if (val > 2147483647.0)
                {
                    val = 2147483647.0;
                }
                if (val < -2147483648.0)
                {
                    val = -2147483648.0;
                }

                wavfile.Write((int)val);
            }
        }
    }
    public static void WriteWaveFile(BinaryFile wavfile, double[][] sound, int channels, int samplecount, int samplerate, int format_param)
    {
        int i = 0;

        int[] tag = { 1179011410, 0, 1163280727, 544501094, 16, 1, 1, 0, 0, 0, 0, 1635017060, 0, 0 };

                #if DEBUG
        Console.Write("WriteWaveFile...\n");
                #endif

        //********WAV tags generation********

        tag[12] = samplecount * (format_param / 8) * channels;
        tag[1]  = tag[12] + 36;
        tag[7]  = samplerate;
        tag[8]  = samplerate * format_param / 8;
        tag[9]  = format_param / 8;
        tag[6]  = channels;
        tag[10] = format_param;

        if ((format_param == 8) || (format_param == 16))
        {
            tag[5] = 1;
        }
        if (format_param == 32)
        {
            tag[5] = 3;
        }
        //--------WAV tags generation--------

        // tag writing
        for (i = 0; i < 13; i++)
        {
            if ((i == 5) || (i == 6) || (i == 9) || (i == 10))
            {
                GlobalMembersUtil.WriteUInt16((ushort)tag[i], wavfile);
            }
            else
            {
                GlobalMembersUtil.WriteUInt32((uint)tag[i], wavfile);
            }
        }

        if (format_param == 8)
        {
            Write8Bit(wavfile, sound, samplecount, channels);
        }
        if (format_param == 16)
        {
            Write16Bit(wavfile, sound, samplecount, channels);
        }
        if (format_param == 32)
        {
            Write32BitFloat(wavfile, sound, samplecount, channels);
        }

        wavfile.Close();
    }
Exemple #5
0
    public static Int32 NextPrime(Int32 x)
    {
        while (GlobalMembersUtil.SmallPrimes(x) != 1)
        {
            x++;
        }

        return(x);
    }
Exemple #6
0
 public static Int32 RoundUp(double x)
 {
     if (GlobalMembersUtil.FMod(x, 1.0) == 0)
     {
         return((Int32)x);
     }
     else
     {
         return((Int32)x + 1);
     }
 }
    public static int GetWaveOutParameters()
    {
        int bps = 0;

        do
        {
            Console.Write("Bits per sample (8/16/32) [16] : ");
            bps = (int)GlobalMembersUtil.GetFloat();
            if (bps == 0)
            {
                bps = 16;
            }
        }while (bps != 8 && bps != 16 && bps != 32);

        return(bps);
    }
Exemple #8
0
    /// <summary>
    /// Downsampling of the signal by a Blackman function
    /// </summary>
    /// <param name="in">Signal</param>
    /// <param name="Mi">Mi is the original signal's length</param>
    /// <param name="Mo">Mo is the output signal's length</param>
    /// <returns>Downsampled Signal</returns>
    public static double[] BlackmanDownsampling(double[] @in, int Mi, int Mo)
    {
        int i = 0;                      // general purpose iterators
        int j = 0;

        double[] @out = new double[Mo];

        double pos_in;                                  // position in the original signal
        double x;                                       // position of the iterator in the blackman(x) formula
        double ratio;                                   // scaling ratio (> 1.0)
        double ratio_i;                                 // ratio^-1
        double coef;                                    // Blackman coefficient
        double coef_sum;                                // sum of coefficients, used for weighting

        /*
         * Mi is the original signal's length
         * Mo is the output signal's length
         */
        ratio   = (double)Mi / Mo;
        ratio_i = 1.0 / ratio;

        for (i = 0; i < Mo; i++)
        {
            pos_in = (double)i * ratio;

            coef_sum = 0;

            for (j = GlobalMembersUtil.RoundUp(pos_in - ratio); j <= pos_in + ratio; j++)
            {
                if (j >= 0 && j < Mi)               // if the read sample is within bounds
                {
                    x         = j - pos_in + ratio; // calculate position within the Blackman function
                    coef      = 0.42 - 0.5 * Math.Cos(PI * x * ratio_i) + 0.08 * Math.Cos(2 * PI * x * ratio_i);
                    coef_sum += coef;
                    @out[i]  += @in[j] * coef;                    // convolve
                }
            }

            @out[i] /= coef_sum;
        }

        return(@out);
    }
Exemple #9
0
 public static double DoubleRandom()
 {
     return(((double)GlobalMembersUtil.Random() * (1.0 / 2147483648.0)) - 1.0);
 }
Exemple #10
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);
    }
Exemple #11
0
    /// <summary>
    /// Sine synthesis mode
    /// </summary>
    /// <param name="d">Image (d is the original image - spectrogram)</param>
    /// <param name="Xsize">Specifies the desired width of the spectrogram</param>
    /// <param name="bands">Specifies the desired height of the spectrogram (total count of bands)</param>
    /// <param name="samplecount">Number of samples (samplecount is the output sound's length)</param>
    /// <param name="samplerate">Sample rate</param>
    /// <param name="basefreq">Minimum 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[] SynthesizeSine(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;                             // s is the output sound
        double[] freq;                          // freq is the band's central frequency
        double[] filter;
        double[] sband;                         // sband is the band's envelope upsampled and shifted up in frequency
        int      sbsize = 0;                    // sbsize is the length of sband

        double[] sine = new double[4];          // sine is the random sine look-up table
        double   rphase;                        // rphase is the band's sine's random phase

        int i  = 0;                             // i is a general purpose iterator
        int ib = 0;                             // ib is the band iterator
        int Fc = 0;                             // Fc is the index of the band's centre in the frequency domain on the new signal
        int Bc = 0;                             // Bc is the index of the band's centre in the frequency domain on sband (its imaginary match being sbsize-Bc)
        int Mh = 0;                             // Mh is the length of the real or imaginary part of the envelope's FFT, DC element included and Nyquist element excluded
        int Mn = 0;                             // Mn is the length of the real or imaginary part of the sound's FFT, DC element included and Nyquist element excluded

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

        clockA = GlobalMembersUtil.GetTime();

        sbsize = GlobalMembersUtil.NextPrime(Xsize * 2);         // In Circular mode keep it to sbsize = Xsize * 2;

        samplecount = (int)GlobalMembersUtil.RoundOff(Xsize / pixpersec);
        Console.Write("Sound duration : {0:f3} s\n", (double)samplecount / samplerate);
        samplecount = (int)GlobalMembersUtil.RoundOff(0.5 * sbsize / pixpersec);       // Do not change this value as it would stretch envelopes

        s = new double[samplecount];

        // allocation of the shifted band
        sband = new double[sbsize];

        // Bc is the index of the band's centre in the frequency domain on sband (its imaginary match being sbsize-Bc)
        Bc = (int)GlobalMembersUtil.RoundOff(0.25 * (double)sbsize);

        // Mh is the length of the real or imaginary part of the envelope's FFT, DC element included and Nyquist element excluded
        Mh = (sbsize + 1) >> 1;
        // Mn is the length of the real or imaginary part of the sound's FFT, DC element included and Nyquist element excluded
        Mn = (samplecount + 1) >> 1;

        filter = GlobalMembersDsp.WindowedSinc_max(Mh, 1.0 / GlobalMembersArss.TRANSITION_BW_SYNT);         // generation of the frequency-domain filter

        for (ib = 0; ib < bands; ib++)
        {
            // reset sband
            for (i = 0; i < sbsize; i++)
            {
                sband[i] = 0;                                  // reset sband
            }
            //********Frequency shifting********
            rphase = GlobalMembersUtil.DoubleRandom() * PI;             // random phase between -pi and +pi

            for (i = 0; i < 4; i++)
            {
                // generating the random sine LUT
                sine[i] = Math.Cos(i * 2.0 * PI * 0.25 + rphase);
            }

            for (i = 0; i < Xsize; i++)             // envelope sampling rate * 2 and frequency shifting by 0.25
            {
                if ((i & 1) == 0)
                {
                    sband[i << 1]       = d[bands - ib - 1][i] * sine[0];
                    sband[(i << 1) + 1] = d[bands - ib - 1][i] * sine[1];
                }
                else
                {
                    sband[i << 1]       = d[bands - ib - 1][i] * sine[2];
                    sband[(i << 1) + 1] = d[bands - ib - 1][i] * sine[3];
                }
            }
            //--------Frequency shifting--------

            GlobalMembersDsp.FFT(ref sband, ref sband, sbsize, FFTMethod.DFT);             // FFT of the envelope

            // Fc is the index of the band's centre in the frequency domain on the new signal
            Fc = (int)GlobalMembersUtil.RoundOff(freq[ib] * samplecount);              // band's centre index (envelope's DC element)

            Console.Write("{0,4:D}/{1:D}   {2:f2} Hz\r", ib + 1, bands, (double)Fc * samplerate / samplecount);

            //********Write FFT********
            for (i = 1; i < Mh; i++)
            {
                if (Fc - Bc + i > 0 && Fc - Bc + i < Mn)                             // if we're between frequencies 0 and 0.5 of the new signal and that we're not at Fc
                {
                    s[i + Fc - Bc] += sband[i] * filter[i];                          // Real part
                    s[samplecount - (i + Fc - Bc)] += sband[sbsize - i] * filter[i]; // Imaginary part
                }
            }
            //--------Write FFT--------
        }

        Console.Write("\n");

        GlobalMembersDsp.FFT(ref s, ref s, samplecount, FFTMethod.IDFT);         // IFFT of the final sound
        samplecount = (int)GlobalMembersUtil.RoundOff(Xsize / pixpersec);        // chopping tails by ignoring them

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

        return(s);
    }
    public static double[][] ReadWaveFile(BinaryFile wavfile, ref int channels, ref int samplecount, ref int samplerate)
    {
        double[][] sound;
        int        i  = 0;
        int        ic = 0;

        int[] tag = new int[13];

        //			Size  Description                  Value
        // tag[0]	4	  RIFF Header				   RIFF (1179011410)
        // tag[1]   4	  RIFF data size
        // tag[2]   4	  form-type (WAVE etc)			(1163280727)
        // tag[3]   4     Chunk ID                     "fmt " (0x666D7420) = 544501094
        // tag[4]	4     Chunk Data Size              16 + extra format bytes
        // tag[5]	2     Compression code             1 - 65,535
        // tag[6]	2     Number of channels           1 - 65,535
        // tag[7]	4     Sample rate                  1 - 0xFFFFFFFF
        // tag[8]	4     Average bytes per second     1 - 0xFFFFFFFF
        // tag[9]	2     Block align                  1 - 65,535 (4)
        // tag[10]	2     Significant bits per sample  2 - 65,535 (32)
        // tag[11]	4	  IEEE = 1952670054 (0x74636166) = fact chunk
        //                PCM = 1635017060 (0x61746164)  (datachunk = 1635017060)
        // tag[12]  4	  IEEE = 4 ,                        PCM = 5292000 (0x0050BFE0)

                #if DEBUG
        Console.Write("ReadWaveFile...\n");
                #endif

        for (i = 0; i < 13; i++)       // tag reading
        {
            tag[i] = 0;

            if ((i == 5) || (i == 6) || (i == 9) || (i == 10))
            {
                tag[i] = GlobalMembersUtil.ReadUInt16(wavfile);
            }
            else
            {
                tag[i] = (int)GlobalMembersUtil.ReadUInt32(wavfile);
            }
        }

        //********File format checking********
        if (tag[0] != 1179011410 || tag[2] != 1163280727)
        {
            Console.Error.WriteLine("This file is not in WAVE format\n");
            GlobalMembersUtil.WinReturn();
            Environment.Exit(1);
        }

        if (tag[3] != 544501094 || tag[4] != 16 || tag[11] != 1635017060)   //
        {
            Console.Error.WriteLine("This WAVE file format is not currently supported\n");
            GlobalMembersUtil.WinReturn();
            Environment.Exit(1);
        }

        if (tag[10] == 24)
        {
            Console.Error.WriteLine("24 bit PCM WAVE files is not currently supported\n");
            GlobalMembersUtil.WinReturn();
            Environment.Exit(1);
        }

        if (tag[5] != WAVE_FORMAT_PCM)
        {
            Console.Error.WriteLine("Non PCM WAVE files is not currently supported\n");
            GlobalMembersUtil.WinReturn();
            Environment.Exit(1);
        }

        //--------File format checking--------

        channels = tag[6];

        samplecount = tag[12] / (tag[10] / 8) / channels;
        samplerate  = tag[7];

        sound = new double[channels][];

        for (ic = 0; ic < channels; ic++)
        {
            sound[ic] = new double[samplecount];
        }

        //********Data loading********
        if (tag[10] == 8)
        {
            Read8Bit(wavfile, sound, samplecount, channels);
        }
        if (tag[10] == 16)
        {
            Read16Bit(wavfile, sound, samplecount, channels);
        }
        if (tag[10] == 32)
        {
            if (tag[5] == WAVE_FORMAT_PCM)
            {
                Read32Bit(wavfile, sound, samplecount, channels);
            }
            else if (tag[5] == WAVE_FORMAT_IEEE_FLOAT)
            {
                Read32BitFloat(wavfile, sound, samplecount, channels);
            }
        }

        //--------Data loading--------

        wavfile.Close();
        return(sound);
    }
Exemple #13
0
    /// <summary>
    /// Interpolation based on an estimate of the Blackman Square function,
    /// which is a Blackman function convolved with a square.
    /// It's like smoothing the result of a nearest neighbour interpolation
    /// with a Blackman FIR
    /// </summary>
    /// <param name="in">Signal in</param>
    /// <param name="out">Signal out</param>
    /// <param name="Mi">Mi is the original signal's length</param>
    /// <param name="Mo">Mo is the output signal's length</param>
    /// <param name="lut">Blackman Square Lookup Table</param>
    /// <param name="lut_size">Defines the number of elements in the Blackman Square look-up table. It's best to make it small enough to be entirely cached</param>
    public static void BlackmanSquareInterpolation(ref double[] @in, ref double[] @out, ref int Mi, ref int Mo, ref double[] lut, int lut_size)
    {
        int    i = 0;        // general purpose iterators
        int    j = 0;
        double pos_in;       // position in the original signal
        double x;            // position of the iterator in the blackman_square(x) formula
        double ratio;        // scaling ratio (> 1.0)
        double ratio_i;      // ratio^-1
        double coef;         // Blackman square final coefficient
        double pos_lut;      // Index on the look-up table
        int    pos_luti = 0; // Integer index on the look-up table
        double mod_pos;      // modulo of the position on the look-up table
        double y0;           // values of the two closest values on the LUT
        double y1;
        double foo     = (double)lut_size / 3.0;
        int    j_start = 0;      // boundary values for the j loop
        int    j_stop  = 0;

        /*
         * Mi is the original signal's length
         * Mo is the output signal's length
         */
        ratio   = (double)Mi / Mo;
        ratio_i = 1.0 / ratio;

        for (i = 0; i < Mo; i++)
        {
            pos_in = (double)i * ratio;

            j_stop = (int)(pos_in + 1.5);

            j_start = j_stop - 2;
            if (j_start < 0)
            {
                j_start = 0;
            }

            // The boundary check is done after j_start is calculated to avoid miscalculating it
            if (j_stop >= Mi)
            {
                j_stop = Mi - 1;
            }

            for (j = j_start; j <= j_stop; j++)
            {
                x        = j - pos_in + 1.5;          // calculate position within the Blackman square function in the [0.0 ; 3.0] range
                pos_lut  = x * foo;
                pos_luti = (int)pos_lut;

                mod_pos = GlobalMembersUtil.FMod(pos_lut, 1.0);                 // modulo of the index

                if (pos_luti + 1 < lut.Length)
                {
                    y0   = lut[pos_luti];                   // interpolate linearly between the two closest values
                    y1   = lut[pos_luti + 1];
                    coef = y0 + mod_pos * (y1 - y0);        // linear interpolation

                    @out[i] += @in[j] * coef;               // convolve
                }
            }
        }
    }
    public static void BMPWrite(BinaryFile bmpfile, double[][] image, int y, int x)
    {
        int    i         = 0; // various iterators
        int    iy        = 0;
        int    ix        = 0;
        int    ic        = 0;
        int    filesize  = 0;
        int    imagesize = 0;
        byte   zerobytes = new byte();
        byte   val       = new byte();
        byte   zero      = 0;
        double vald;

                #if DEBUG
        Console.Write("BMPWrite...\n");
                #endif

        zerobytes = (byte)(4 - ((x * 3) & 3));         // computation of zero bytes
        if (zerobytes == 4)
        {
            zerobytes = 0;
        }

        //********Tags********
        filesize  = 56 + ((x * 3) + zerobytes) * y;
        imagesize = 2 + ((x * 3) + zerobytes) * y;

        GlobalMembersUtil.WriteUInt16(19778, bmpfile);
        GlobalMembersUtil.WriteUInt32((UInt32)filesize, bmpfile);
        GlobalMembersUtil.WriteUInt32(0, bmpfile);
        GlobalMembersUtil.WriteUInt32(54, bmpfile);
        GlobalMembersUtil.WriteUInt32(40, bmpfile);
        GlobalMembersUtil.WriteUInt32((UInt32)x, bmpfile);
        GlobalMembersUtil.WriteUInt32((UInt32)y, bmpfile);
        GlobalMembersUtil.WriteUInt16(1, bmpfile);
        GlobalMembersUtil.WriteUInt32(24, bmpfile);
        GlobalMembersUtil.WriteUInt16(0, bmpfile);
        GlobalMembersUtil.WriteUInt32((UInt32)imagesize, bmpfile);
        GlobalMembersUtil.WriteUInt32(2834, bmpfile);
        GlobalMembersUtil.WriteUInt32(2834, bmpfile);
        GlobalMembersUtil.WriteUInt32(0, bmpfile);
        GlobalMembersUtil.WriteUInt32(0, bmpfile);
        //--------Tags--------

        for (iy = y - 1; iy != -1; iy--)       // backwards writing
        {
            for (ix = 0; ix < x; ix++)
            {
                // define color
                vald = image[iy][ix] * 255.0;

                if (vald > 255.0)
                {
                    vald = 255.0;
                }

                if (vald < 0.0)
                {
                    vald = 0.0;
                }

                val = (byte)vald;

                for (ic = 2; ic != -1; ic--)
                {
                    bmpfile.Write(val);
                }
            }

            // write padding bytes
            for (i = 0; i < zerobytes; i++)
            {
                bmpfile.Write(zero);
            }
        }

        GlobalMembersUtil.WriteUInt16(0, bmpfile);

        bmpfile.Close();

                #if DEBUG
        Console.Write("Image size : {0:D}x{1:D}\n", x, y);
                #endif
    }
    public static double[][] BMPRead(BinaryFile bmpfile, ref int y, ref int x)
    {
        int iy     = 0;     // various iterators
        int ix     = 0;
        int ic     = 0;
        int offset = 0;

        double[][] image;
        byte       zerobytes = new byte();
        byte       val       = new byte();

                #if DEBUG
        Console.Write("BMPRead...\n");
                #endif

        if (GlobalMembersUtil.ReadUInt16(bmpfile) != 19778)         // "BM" format tag check
        {
            Console.Error.WriteLine("This file is not in BMP format\n");
            GlobalMembersUtil.WinReturn();
            Environment.Exit(1);
        }

        bmpfile.Seek(8, SeekOrigin.Current);                      // skipping useless tags

        offset = (int)GlobalMembersUtil.ReadUInt32(bmpfile) - 54; // header offset

        bmpfile.Seek(4, SeekOrigin.Current);                      // skipping useless tags

        x = (int)GlobalMembersUtil.ReadUInt32(bmpfile);
        y = (int)GlobalMembersUtil.ReadUInt32(bmpfile);

        bmpfile.Seek(2, SeekOrigin.Current);             // skipping useless tags

        if (GlobalMembersUtil.ReadUInt16(bmpfile) != 24) // Only format supported
        {
            Console.Error.WriteLine("Wrong BMP format, BMP images must be in 24-bit colour\n");
            GlobalMembersUtil.WinReturn();
            Environment.Exit(1);
        }

        bmpfile.Seek(24 + offset, SeekOrigin.Current);       // skipping useless tags

        // image allocation
        image = new double[y][];

        for (iy = 0; iy < y; iy++)
        {
            image[iy] = new double[x];
        }

        zerobytes = (byte)(4 - ((x * 3) & 3));
        if (zerobytes == 4)
        {
            zerobytes = 0;
        }

        for (iy = y - 1; iy != -1; iy--)       // backwards reading
        {
            for (ix = 0; ix < x; ix++)
            {
                for (ic = 2; ic != -1; ic--)
                {
                    val            = bmpfile.ReadByte();
                    image[iy][ix] += (double)val * (1.0 / (255.0 * 3.0));                    // Conversion to grey by averaging the three channels
                }
            }

            bmpfile.Seek(zerobytes, SeekOrigin.Current);             // skipping padding bytes
        }

        bmpfile.Close();
        return(image);
    }
Exemple #16
0
    public static void Main(string[] args)
    {
        /*
         * CommonUtils.FFT.FFTTesting.TimeSpectrograms();
         * Console.ReadKey();
         * return;
         *
         * int _channels = 0;
         * int _samplecount = 0;
         * int _samplerate = 0;
         * string _filenameIn = @"C:\Users\perivar.nerseth\Music\Sleep Away16.wav";
         * string _filenameOut = @"C:\Users\perivar.nerseth\Music\Sleep Away16-test2.png";
         * double[][] _sound = GlobalMembersSoundIO.ReadWaveFile(_filenameIn, ref _channels, ref _samplecount, ref _samplerate); // Sound input
         * double [] _s = _sound[0];
         *
         * Spectrogram spectrogram = new Spectrogram();
         * Bitmap bmp  = spectrogram.to_image(ref _s, _samplerate);
         * bmp.Save(_filenameOut);
         * Console.ReadKey();
         * return;
         * double[] out1 = new double[_samplecount];
         * double[] out2 = new double[_samplecount];
         * GlobalMembersDsp.FFT(ref _s, ref out1, _samplecount, GlobalMembersDsp.FFTMethod.DFT);
         * GlobalMembersDsp.FFT(ref out1, ref out2, _samplecount, GlobalMembersDsp.FFTMethod.IDFT);
         *
         * _sound[0] = out2;
         *
         * BinaryFile binOut = new BinaryFile(_filenameOut, BinaryFile.ByteOrder.LittleEndian, true);
         * GlobalMembersSoundIO.WriteWaveFile(binOut, _sound, 1, _samplecount, _samplerate, 16);
         *
         * Console.ReadKey();
         * return;
         */

        int argc = args.Length;

        BinaryFile fin;
        BinaryFile fout;

        int i = 0;

        double[][] sound;
        double[][] image;
        double     basefreq     = 0;
        double     maxfreq      = 0;
        double     pixpersec    = 0;
        double     bpo          = 0;
        double     brightness   = 1;
        int        channels     = 0;
        int        samplecount  = 0;
        int        samplerate   = 0;
        int        Xsize        = 0;
        int        Ysize        = 0;
        int        format_param = 0;
        long       clockb       = 0;
        byte       mode         = 0;
        string     in_name      = null;
        string     out_name     = null;

        // initialisation of global using defaults defined in dsp.h
        GlobalMembersDsp.PI            = PI_D;
        GlobalMembersDsp.LOGBASE       = LOGBASE_D;
        GlobalMembersDsp.LOOP_SIZE_SEC = LOOP_SIZE_SEC_D;
        GlobalMembersDsp.BMSQ_LUT_SIZE = BMSQ_LUT_SIZE_D;

                #if QUIET
        GlobalMembersUtil.quiet = true;
                #else
        GlobalMembersUtil.quiet = false;
                #endif

        Console.Write("The Analysis & Resynthesis Sound Spectrograph {0}\n", version);

        RandomNumbers.Seed((int)DateTime.Now.Millisecond);

        bool doHelp = false;
        for (i = 0; i < argc; i++)
        {
            if (string.Compare(args[i], "/?") == 0)           // DOS friendly help
            {
                doHelp = true;
            }

            if (args[i][0] != '-')             // if the argument is not a function
            {
                if (in_name == null)           // if the input file name hasn't been filled in yet
                {
                    in_name = args[i];
                }
                else
                if (out_name == null)                         // if the input name has been filled but not the output name yet
                {
                    out_name = args[i];
                }
                else                         // if both names have already been filled in
                {
                    Console.Error.WriteLine("You can only have two file names as parameters.\nRemove parameter \"%s\".\nExiting with error.\n", args[i]);
                    Environment.Exit(1);
                }
            }
            else             // if the argument is a parameter
            {
                if (string.Compare(args[i], "--analysis") == 0 || string.Compare(args[i], "-a") == 0)
                {
                    mode = 1;
                }

                if (string.Compare(args[i], "--sine") == 0 || string.Compare(args[i], "-s") == 0)
                {
                    mode = 2;
                }

                if (string.Compare(args[i], "--noise") == 0 || string.Compare(args[i], "-n") == 0)
                {
                    mode = 3;
                }

                if (string.Compare(args[i], "--quiet") == 0 || string.Compare(args[i], "-q") == 0)
                {
                    GlobalMembersUtil.quiet = true;
                }

                if (string.Compare(args[i], "--linear") == 0 || string.Compare(args[i], "-l") == 0)
                {
                    GlobalMembersDsp.LOGBASE = 1.0;
                }

                if (string.Compare(args[i], "--sample-rate") == 0 || string.Compare(args[i], "-r") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        samplerate = Convert.ToInt32(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--min-freq") == 0 || string.Compare(args[i], "-min") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        basefreq = Convert.ToDouble(args[i]);
                        if (basefreq == 0)
                        {
                            basefreq = Double.MinValue;                     // Set it to this extremely close-to-zero number so that it's considered set
                        }
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--max-freq") == 0 || string.Compare(args[i], "-max") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        maxfreq = Convert.ToDouble(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--bpo") == 0 || string.Compare(args[i], "-b") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        bpo = Convert.ToDouble(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--pps") == 0 || string.Compare(args[i], "-p") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        pixpersec = Convert.ToDouble(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--height") == 0 || string.Compare(args[i], "-y") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        Ysize = Convert.ToInt32(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--width") == 0 || string.Compare(args[i], "-x") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        Xsize = Convert.ToInt32(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--loop-size") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        GlobalMembersDsp.LOOP_SIZE_SEC = Convert.ToInt32(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--log-base") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        GlobalMembersDsp.LOGBASE = Convert.ToDouble(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--bmsq-lut-size") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        GlobalMembersDsp.BMSQ_LUT_SIZE = Convert.ToInt32(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--pi") == 0)               // lol
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        GlobalMembersDsp.PI = Convert.ToDouble(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--format-param") == 0 || string.Compare(args[i], "-f") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        format_param = Convert.ToInt32(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                if (string.Compare(args[i], "--brightness") == 0 || string.Compare(args[i], "-g") == 0)
                {
                    if (StringUtils.IsNumeric(args[++i]))
                    {
                        brightness = Convert.ToDouble(args[i]);
                    }
                    else
                    {
                        Console.Error.WriteLine(MSG_NUMBER_EXPECTED, args[i - 1]);
                        Environment.Exit(1);
                    }
                }

                // TODO implement --duration, -d

                if (string.Compare(args[i], "--version") == 0 || string.Compare(args[i], "-v") == 0)
                {
                    Console.Write("Copyright (C) 2005-2008 Michel Rouzic\nProgram last modified by its author on {0}\n", date);
                    Environment.Exit(0);
                }

                if (doHelp || string.Compare(args[i], "--help") == 0 || string.Compare(args[i], "-h") == 0)
                {
                    GlobalMembersArss.PrintHelp();
                    Environment.Exit(0);
                }

                if (string.Compare(args[i], "--adv-help") == 0)
                {
                    GlobalMembersArss.PrintAdvancedHelp();
                    Environment.Exit(0);
                }
            }
        }

        if (in_name != null)               // if in_name has already been filled in
        {
            fin = new BinaryFile(in_name); // try to open it
            if (fin == null)
            {
                Console.Error.WriteLine("The input file {0} could not be found\nExiting with error.\n", in_name);
                Environment.Exit(1);
            }
            Console.Write("Input file : {0}\n", in_name);
        }
        else
        {
            if (GlobalMembersUtil.quiet)
            {
                Console.Error.WriteLine("Please specify an input file.\nExiting with error.\n");
                Environment.Exit(1);
            }

            Console.Write("Type 'help' to read the manual page\n");

            do
            {
                fin = null;
                Console.Write("Input file : ");
                in_name = GlobalMembersUtil.GetString();

                if (string.Compare(in_name, "help") == 0)                 // if 'help' has been typed
                {
                    fin = null;
                    GlobalMembersArss.PrintHelp();                     // print the help
                }
                else
                {
                    if (File.Exists(in_name))
                    {
                        fin = new BinaryFile(in_name);
                    }
                }
            }while (fin == null);
        }

        if (out_name != null)         // if out_name has already been filled in
        {
            fout = new BinaryFile(out_name, BinaryFile.ByteOrder.LittleEndian, true);
            if (fout == null)
            {
                Console.Error.WriteLine("The output file {0} could not be opened.\nPlease make sure it isn't opened by any other program and press Return.\nExiting with error.\n", out_name);
                Environment.Exit(1);
            }
            Console.Write("Output file : {0}\n", out_name);
        }
        else
        {
            if (GlobalMembersUtil.quiet)
            {
                Console.Error.WriteLine("Please specify an output file.\nExiting with error.\n");
                Environment.Exit(1);
            }
            Console.Write("Output file : ");
            out_name = GlobalMembersUtil.GetString();

            fout = null;
            if (out_name != null && out_name != "")
            {
                fout = new BinaryFile(out_name, BinaryFile.ByteOrder.LittleEndian, true);
            }

            while (fout == null)
            {
                Console.Write("Output file : ");
                out_name = GlobalMembersUtil.GetString();

                if (out_name != null && out_name != "")
                {
                    fout = new BinaryFile(out_name, BinaryFile.ByteOrder.LittleEndian, true);
                }
            }

            // we will never get here cause BinaryFile does not return a null
            while (fout == null)
            {
                Console.Error.WriteLine("The output file {0} could not be opened.\nPlease make sure it isn't opened by any other program and press Return.\n", out_name);
                Console.Read();

                fout = new BinaryFile(out_name, BinaryFile.ByteOrder.LittleEndian, true);
            }
        }

        // make the string lowercase
        in_name = in_name.ToLower();
        if (mode == 0 && in_name.EndsWith(".wav"))
        {
            mode = 1;             // Automatic switch to the Analysis mode
        }

        if (mode == 0)
        {
            do
            {
                if (GlobalMembersUtil.quiet)
                {
                    Console.Error.WriteLine("Please specify an operation mode.\nUse either --analysis (-a), --sine (-s) or --noise (-n).\nExiting with error.\n");
                    Environment.Exit(1);
                }
                Console.Write("Choose the mode (Press 1, 2 or 3) :\n\t1. Analysis\n\t2. Sine synthesis\n\t3. Noise synthesis\n> ");
                mode = (byte)GlobalMembersUtil.GetFloat();
            }while (mode != 1 && mode != 2 && mode != 3);
        }


        if (mode == 1)
        {
            //sound = GlobalMembersSound_io.wav_in(fin, ref channels, ref samplecount, ref samplerate); // Sound input
            fin.Close();
            sound = GlobalMembersSoundIO.ReadWaveFile(in_name, ref channels, ref samplecount, ref samplerate);             // Sound input

                        #if DEBUG
            Console.Write("samplecount : {0:D}\nchannels : {1:D}\n", samplecount, channels);
                        #endif

            GlobalMembersArss.SettingsInput(ref Ysize, ref samplecount, ref samplerate, ref basefreq, ref maxfreq, ref pixpersec, ref bpo, ref Xsize, 0);            // User settings input
            image = GlobalMembersDsp.Analyze(ref sound[0], ref samplecount, ref samplerate, ref Xsize, ref Ysize, ref bpo, ref pixpersec, ref basefreq);             // Analysis
            if (brightness != 1.0)
            {
                GlobalMembersDsp.BrightnessControl(ref image, ref Ysize, ref Xsize, 1.0 / brightness);
            }

            GlobalMembersImageIO.BMPWrite(fout, image, Ysize, Xsize);             // Image output
        }

        if (mode == 2 || mode == 3)
        {
            sound = new double[1][];

            image = GlobalMembersImageIO.BMPRead(fin, ref Ysize, ref Xsize);             // Image input

            // if the output format parameter is undefined
            if (format_param == 0)
            {
                if (!GlobalMembersUtil.quiet)                   // if prompting is allowed
                {
                    format_param = GlobalMembersSoundIO.GetWaveOutParameters();
                }
                else
                {
                    format_param = 32;                     // default is 32
                }
            }

            GlobalMembersArss.SettingsInput(ref Ysize, ref samplecount, ref samplerate, ref basefreq, ref maxfreq, ref pixpersec, ref bpo, ref Xsize, 1);             // User settings input

            if (brightness != 1.0)
            {
                GlobalMembersDsp.BrightnessControl(ref image, ref Ysize, ref Xsize, brightness);
            }

            if (mode == 2)
            {
                sound[0] = GlobalMembersDsp.SynthesizeSine(ref image, ref Xsize, ref Ysize, ref samplecount, ref samplerate, ref basefreq, ref pixpersec, ref bpo);                 // Sine synthesis
            }
            else
            {
                sound[0] = GlobalMembersDsp.SynthesizeNoise(ref image, ref Xsize, ref Ysize, ref samplecount, ref samplerate, ref basefreq, ref pixpersec, ref bpo);                 // Noise synthesis
            }

            GlobalMembersSoundIO.WriteWaveFile(fout, sound, 1, samplecount, samplerate, format_param);
        }

        clockb = GlobalMembersUtil.GetTime();
        TimeSpan duration = TimeSpan.FromTicks((clockb - GlobalMembersDsp.clockA));
        Console.Write("Processing time : {0:D2} m  {1:D2} s  {1:D2} ms\n", duration.Minutes, duration.Seconds, duration.Milliseconds);

        GlobalMembersUtil.WinReturn();
    }
Exemple #17
0
    /// <summary>
    /// Get Settings from User Input or Config file
    /// </summary>
    /// <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="maxfreq">Maximum frequency in Hertz</param>
    /// <param name="pixpersec">Time resolution in Pixels Per Second</param>
    /// <param name="bandsperoctave">Frequency resolution in Bands Per Octave</param>
    /// <param name="Xsize">Specifies the desired width of the spectrogram</param>
    /// <param name="mode">0 = Analysis mode, 1 = Synthesis mode</param>
    public static void SettingsInput(ref int bands, ref int samplecount, ref int samplerate, ref double basefreq, ref double maxfreq, ref double pixpersec, ref double bandsperoctave, ref int Xsize, int mode)
    {
        /* mode :
         * 0 = Analysis mode
         * 1 = Synthesis mode
         */
        int    i = 0;
        double gf;
        double f;
        double trash;
        double ma;          // maximum allowed frequency
        int    unset   = 0; // count of unset interdependant settings
        int    set_min = 0;
        int    set_max = 0;
        int    set_bpo = 0;
        int    set_y   = 0;
        int    set_pps = 0;
        int    set_x   = 0;

                #if DEBUG
        Console.Write("settingsinput...\n");
                #endif

        // Path to the configuration file
        string     configFileName = "arss.conf";
        TextReader freqcfg        = null;
        if (File.Exists(configFileName))
        {
            freqcfg = new StreamReader(configFileName);
        }

        if (samplerate == 0)         // if we're in synthesis mode and that no samplerate has been defined yet
        {
            if (GlobalMembersUtil.quiet)
            {
                Console.Error.WriteLine("Please provide a sample rate for your output sound.\nUse --sample-rate (-r).\nExiting with error.\n");
                Environment.Exit(1);
            }
            //********Output settings querying********

            Console.Write("Sample rate [44100] : ");         // Query for a samplerate
            samplerate = (int)GlobalMembersUtil.GetFloat();
            if (samplerate == 0 || samplerate < -2147483647) // The -2147483647 check is used for the sake of compatibility with C90
            {
                samplerate = 44100;                          // Default value
            }
            //--------Output settings querying--------
        }

        if (basefreq != 0)         // count unset interdependant frequency-domain settings
        {
            set_min = 1;
        }

        if (maxfreq != 0)
        {
            set_max = 1;
        }

        if (bandsperoctave != 0)
        {
            set_bpo = 1;
        }

        if (bands != 0)
        {
            set_y = 1;
        }

        unset = set_min + set_max + set_bpo + set_y;

        if (unset == 4)         // if too many settings are set
        {
            if (mode == 0)
            {
                Console.Error.WriteLine("You have set one parameter too many.\nUnset either --min-freq (-min), --max-freq (-max), --bpo (-b)\nExiting with error.\n");
            }
            if (mode == 1)
            {
                Console.Error.WriteLine("You have set one parameter too many.\nUnset either --min-freq (-min), --max-freq (-max), --bpo (-b) or --height (-y)\nExiting with error.\n");
            }
            Environment.Exit(1);
        }

        if (pixpersec != 0)
        {
            set_pps = 1;
        }

        if (Xsize != 0)
        {
            set_x = 1;
        }

        if (set_x + set_pps == 2 && mode == 0)
        {
            Console.Error.WriteLine("You cannot define both the image width and the horizontal resolution.\nUnset either --pps (-p) or --width (-x)\nExiting with error.\n");
            Environment.Exit(1);
        }

        if (freqcfg != null)         // load settings from file if it exists
        {
            if (basefreq == 0)       // load values from it if they haven't been set yet
            {
                basefreq = double.Parse(freqcfg.ReadLine());
            }
            else
            {
                trash = double.Parse(freqcfg.ReadLine());
            }

            if (maxfreq == 0)
            {
                maxfreq = double.Parse(freqcfg.ReadLine());
            }
            else
            {
                trash = double.Parse(freqcfg.ReadLine());
            }

            if (bandsperoctave == 0)
            {
                bandsperoctave = double.Parse(freqcfg.ReadLine());
            }
            else
            {
                trash = double.Parse(freqcfg.ReadLine());
            }

            if (pixpersec == 0)
            {
                pixpersec = double.Parse(freqcfg.ReadLine());
            }
            else
            {
                trash = double.Parse(freqcfg.ReadLine());
            }
        }
        else
        {
            if (basefreq == 0)             // otherwise load default values
            {
                basefreq = 27.5;
            }
            if (maxfreq == 0)
            {
                maxfreq = 20000;
            }
            if (bandsperoctave == 0)
            {
                bandsperoctave = 12;
            }
            if (pixpersec == 0)
            {
                pixpersec = 150;
            }
        }
        if (freqcfg != null)
        {
            freqcfg.Close();
        }

        if (unset < 3 && set_min == 0)
        {
            if (GlobalMembersUtil.quiet)
            {
                Console.Error.WriteLine("Please define a minimum frequency.\nUse --min-freq (-min).\nExiting with error.\n");
                Environment.Exit(1);
            }
            Console.Write("Min. frequency (Hz) [{0:f3}]: ", basefreq);
            gf = GlobalMembersUtil.GetFloat();
            if (gf != 0)
            {
                basefreq = gf;
            }
            unset++;
            set_min = 1;
        }
        basefreq /= samplerate;         // turn basefreq from Hz to fractions of samplerate

        if (unset < 3 && set_bpo == 0)
        {
            if (GlobalMembersUtil.quiet)
            {
                Console.Error.WriteLine("Please define a bands per octave setting.\nUse --bpo (-b).\nExiting with error.\n");
                Environment.Exit(1);
            }
            Console.Write("Bands per octave [{0:f3}]: ", bandsperoctave);
            gf = GlobalMembersUtil.GetFloat();
            if (gf != 0)
            {
                bandsperoctave = gf;
            }
            unset++;
            set_bpo = 1;
        }

        if (unset < 3 && set_max == 0)
        {
            i = 0;
            do
            {
                i++;
                f = basefreq * Math.Pow(GlobalMembersDsp.LOGBASE, (i / bandsperoctave));
            }while (f < 0.5);

            ma = basefreq * Math.Pow(GlobalMembersDsp.LOGBASE, ((i - 2) / bandsperoctave)) * samplerate;           // max allowed frequency

            if (maxfreq > ma)
            {
                if (GlobalMembersUtil.FMod(ma, 1.0) == 0.0)
                {
                    maxfreq = ma;                     // replaces the "Upper frequency limit above Nyquist frequency" warning
                }
                else
                {
                    maxfreq = ma - GlobalMembersUtil.FMod(ma, 1.0);
                }
            }

            if (mode == 0)             // if we're in Analysis mode
            {
                if (GlobalMembersUtil.quiet)
                {
                    Console.Error.WriteLine("Please define a maximum frequency.\nUse --max-freq (-max).\nExiting with error.\n");
                    Environment.Exit(1);
                }
                Console.Write("Max. frequency (Hz) (up to {0:f3}) [{1:f3}]: ", ma, maxfreq);
                gf = GlobalMembersUtil.GetFloat();
                if (gf != 0)
                {
                    maxfreq = gf;
                }

                if (maxfreq > ma)
                {
                    if (GlobalMembersUtil.FMod(ma, 1.0) == 0.0)
                    {
                        maxfreq = ma;                         // replaces the "Upper frequency limit above Nyquist frequency" warning
                    }
                    else
                    {
                        maxfreq = ma - GlobalMembersUtil.FMod(ma, 1.0);
                    }
                }
            }

            unset++;
            set_max = 1;
        }

        if (set_min == 0)
        {
            basefreq = Math.Pow(GlobalMembersDsp.LOGBASE, (bands - 1) / bandsperoctave) * maxfreq;           // calculate the lower frequency in Hz
            Console.Write("Min. frequency : {0:f3} Hz\n", basefreq);
            basefreq /= samplerate;
        }

        if (set_max == 0)
        {
            maxfreq = Math.Pow(GlobalMembersDsp.LOGBASE, (bands - 1) / bandsperoctave) * (basefreq * samplerate);           // calculate the upper frequency in Hz
            Console.Write("Max. frequency : {0:f3} Hz\n", maxfreq);
        }

        if (set_y == 0)
        {
            bands = 1 + (int)GlobalMembersUtil.RoundOff(bandsperoctave * (GlobalMembersUtil.Log(maxfreq) - GlobalMembersUtil.Log(basefreq * samplerate)));
            Console.Write("Bands : {0:D}\n", bands);
        }

        if (set_bpo == 0)
        {
            if (GlobalMembersDsp.LOGBASE == 1.0)
            {
                bandsperoctave = maxfreq / samplerate;
            }
            else
            {
                bandsperoctave = (bands - 1) / (GlobalMembersUtil.Log(maxfreq) - GlobalMembersUtil.Log(basefreq * samplerate));
            }
            Console.Write("Bands per octave : {0:f3}\n", bandsperoctave);
        }

        if (set_x == 1 && mode == 0)                                              // If we're in Analysis mode and that X is set (by the user)
        {
            pixpersec = (double)Xsize * (double)samplerate / (double)samplecount; // calculate pixpersec
            Console.Write("Pixels per second : {0:f3}\n", pixpersec);
        }

        if ((mode == 0 && set_x == 0 && set_pps == 0) || (mode == 1 && set_pps == 0))         // If in Analysis mode none are set or pixpersec isn't set in Synthesis mode
        {
            if (GlobalMembersUtil.quiet)
            {
                Console.Error.WriteLine("Please define a pixels per second setting.\nUse --pps (-p).\nExiting with error.\n");
                Environment.Exit(1);
            }
            Console.Write("Pixels per second [{0:f3}]: ", pixpersec);
            gf = GlobalMembersUtil.GetFloat();
            if (gf != 0)
            {
                pixpersec = gf;
            }
        }

        basefreq *= samplerate;                                   // turn back to Hz just for the sake of writing to the file

        TextWriter freqcfgOut = new StreamWriter(configFileName); // saving settings to a file

        if (freqcfgOut == null)
        {
            Console.Error.WriteLine("Cannot write to configuration file");
            Environment.Exit(1);
        }
        freqcfgOut.WriteLine(basefreq);
        freqcfgOut.WriteLine(maxfreq);
        freqcfgOut.WriteLine(bandsperoctave);
        freqcfgOut.WriteLine(pixpersec);
        freqcfgOut.Close();

        basefreq  /= samplerate;        // basefreq is now in fraction of the sampling rate instead of Hz
        pixpersec /= samplerate;        // pixpersec is now in fraction of the sampling rate instead of Hz
    }
Exemple #18
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);
    }