示例#1
0
        public Bitmap MakeImage(List <double[]> data)
        {
            Console.Out.WriteLine("Generating image");

            int height = data.Count;
            int width  = data[0].Length;

            Console.Write("Image size: ");
            Console.Write(width);
            Console.Write(" x ");
            Console.Write(height);
            Console.Write("\n");

            // using PixelFormat.Format24bppRgb makes setpixel horribly slow
            //var @out = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            var @out = new Bitmap(width, height);

            BrightCorrection correction = BrightCorrection.BRIGHT_NONE;

            for (int y = 0; y < height; ++y)
            {
                Debug.Assert(data[y].Length == width);

                for (int x = 0; x < width; ++x)
                {
                    double intensity = SpectrogramUtils.CalcIntensity(data[y][x], intensity_axis);
                    intensity = SpectrogramUtils.BrightnessCorrection(intensity, correction);
                    @out.SetPixel(x, (int)(height - 1 - y), palette.GetColor(intensity));
                }
            }

            //@out.SetText("Spectrogram", serialized()); // save parameters
            return(@out);
        }
示例#2
0
        public static double WindowCoef(double x, Window window)
        {
            Debug.Assert(x >= 0 && x <= 1);

            if (window == Window.WINDOW_RECTANGULAR)
            {
                return(1.0);
            }
            switch (window)
            {
            case Window.WINDOW_HANN:
                return(SpectrogramUtils.HannWindow(x));

            case Window.WINDOW_BLACKMAN:
                return(SpectrogramUtils.BlackmanWindow(x));

            case Window.WINDOW_TRIANGULAR:
                return(SpectrogramUtils.TriangularWindow(x));

            default:
                Debug.Assert(false);
                break;
            }
            return(0.0);
        }
示例#3
0
        public LogFilterbank(double scale, double @base, double centsperband, double overlap)
        {
            scale_        = scale;
            centsperband_ = centsperband;
            logstart_     = SpectrogramUtils.Freq2Cent(@base);
            logstep_      = (1 - overlap) * centsperband_;

            Console.Out.WriteLine("Cents per band: {0}", centsperband_);
            Console.Out.WriteLine("Logstep: {0}", logstep_);
            Debug.Assert(logstep_ > 0);
        }
示例#4
0
        // TODO: this method takes a long time - why?
        public double[] EnvelopeFromSpectrogram(Bitmap image, int row)
        {
            var envelope = new double[image.Width];

            for (int x = 0; x < image.Width; ++x)
            {
                envelope[x] = SpectrogramUtils.CalcIntensityInv(
                    palette.GetIntensity(image.GetPixel(x, image.Height - row - 1)), intensity_axis);
            }
            return(envelope);
        }
示例#5
0
        public override Pair <int, int> GetBand(int i)
        {
            double logcenter = logstart_ + i * logstep_;
            double loglow    = logcenter - centsperband_ / 2.0;
            double loghigh   = loglow + centsperband_;
            var    @out      = new Pair <int, int>();

            @out.First  = (int)(SpectrogramUtils.Cent2Freq(loglow) * scale_);
            @out.Second = (int)(SpectrogramUtils.Cent2Freq(loghigh) * scale_);

            //Console.Out.WriteLine("Center freq: {0}", SpectrogramUtils.Cent2Freq(logcenter));
            //Console.Out.WriteLine("Low freq: {0}, Highfreq: {1}", SpectrogramUtils.Cent2Freq(loglow), SpectrogramUtils.Cent2Freq(loghigh));
            return(@out);
        }
示例#6
0
        public double[] SynthetizeNoise(Bitmap image, int samplerate)
        {
            using (new DebugTimer("Spectrogram: SynthetizeNoise()"))
            {
                int samples = (int)image.Width * samplerate / pixpersec;

                Complex[] noise = SpectrogramUtils.GetPinkNoise(samplerate * 10);                 // 10 sec loop

                double     filterscale = ((double)noise.Length * 2) / samplerate;
                Filterbank filterbank  = Filterbank.GetFilterbank(frequency_axis, filterscale, basefreq, bandwidth, overlap);

                int top_index = (int)(maxfreq * filterscale);

                var @out = new double[samples];

                for (int bandidx = 0; bandidx < image.Height; ++bandidx)
                {
                    //if (cancelled())
                    //	return List<int>();
                    OutputBandProgress(bandidx, image.Height - 1);

                    // filter noise
                    Pair <int, int> range = filterbank.GetBand(bandidx);
                    //std::cout << bandidx << "/"<<image.height()<<"\n";
                    Console.Out.WriteLine("(noise) sample: {0}", range.Second - range.First);

                    var filtered_noise = new Complex[noise.Length];
                    // TODO: copy noise into filtered_noise array
                    //std.copy(noise.begin()+range.first, noise.begin()+Math.Min(range.second, top_index), filtered_noise.begin()+range.first);

                    //apply_window(filtered_noise, range.first, filterscale);

                    // ifft noise
                    double[] noise_mod = SpectrogramUtils.padded_IFFT(ref filtered_noise);

                    // resample spectrogram band
                    double[] envelope = SpectrogramUtils.Resample(EnvelopeFromSpectrogram(image, bandidx), samples);

                    // modulate with looped noise
                    for (uint i = 0; i < samples; ++i)
                    {
                        @out[i] += envelope[i] * noise_mod[i % noise_mod.Length];
                    }
                }

                SpectrogramUtils.NormalizeSignal(ref @out);
                return(@out);
            }
        }
示例#7
0
        public static double CalcIntensityInv(double val, AxisScale intensity_axis)
        {
            Debug.Assert(val >= 0 && val <= 1);
            switch (intensity_axis)
            {
            case AxisScale.SCALE_LOGARITHMIC:
                return(SpectrogramUtils.Log10ScaleInverse(val));

            case AxisScale.SCALE_LINEAR:
                return(val);

            default:
                Debug.Assert(false);
                break;
            }
            return(0.0);
        }
示例#8
0
        public void ApplyWindow(ref Complex[] chunk, int lowidx, double filterscale)
        {
            int highidx = lowidx + chunk.Length;

            if (frequency_axis == AxisScale.SCALE_LINEAR)
            {
                for (int i = 0; i < chunk.Length; ++i)
                {
                    chunk[i] *= SpectrogramUtils.WindowCoef((double)i / (chunk.Length - 1), window);
                }
            }
            else
            {
                double rloglow  = SpectrogramUtils.Freq2Cent(lowidx / filterscale);              // after rounding
                double rloghigh = SpectrogramUtils.Freq2Cent((highidx - 1) / filterscale);
                for (int i = 0; i < chunk.Length; ++i)
                {
                    double logidx = SpectrogramUtils.Freq2Cent((lowidx + i) / filterscale);
                    double winidx = (logidx - rloglow) / (rloghigh - rloglow);
                    chunk[i] *= SpectrogramUtils.WindowCoef(winidx, window);
                }
            }
        }
示例#9
0
        public override double GetCenter(int i)
        {
            double logcenter = logstart_ + i * logstep_;

            return(SpectrogramUtils.Cent2Freq(logcenter) * scale_);
        }
示例#10
0
 public override double NumBandsEst(double maxfreq)
 {
     return((SpectrogramUtils.Freq2Cent(maxfreq) - logstart_) / logstep_ + 4);
 }
示例#11
0
        public Bitmap ToImage(ref double[] signal, int samplerate)
        {
            using (new DebugTimer("Spectrogram: ToImage()"))
            {
                Console.Out.WriteLine("Spectrogram: Transform Sound to Image");

                Complex[] spectrum = SpectrogramUtils.padded_FFT(ref signal);

                //const size_t width = (spectrum.size()-1)*2*pixpersec/samplerate;
                double lastSpectrumIndex = spectrum.Length - 1;                 // last spectrum index
                double pixelsPerSample   = (double)pixpersec / (double)samplerate;
                double widthDouble       = lastSpectrumIndex * 2 * pixelsPerSample;
                int    width             = MathUtils.RoundAwayFromZero(widthDouble);
                Console.Out.WriteLine("Width: {0}", width);
                //int testWidt = (int) (signal.Length * pixpersec);

                // transformation of frequency in hz to index in spectrum
                double filterscale = ((double)spectrum.Length * 2) / samplerate;
                Console.Out.WriteLine("Filterscale: {0}", filterscale);

                Filterbank filterbank = Filterbank.GetFilterbank(frequency_axis, filterscale, basefreq, bandwidth, overlap);
                int        bands      = (int)filterbank.NumBandsEst(maxfreq);
                int        top_index  = (int)((double)maxfreq * filterscale);

                // maxfreq has to be at most nyquist
                Debug.Assert(top_index <= spectrum.Length);

                //std::vector<real_vec> image_data;
                var image_data = new List <double[]>();

                for (int bandidx = 0;; ++bandidx)
                {
                    // TODO: support cancelling this process

                    // filtering
                    Pair <int, int> range = filterbank.GetBand(bandidx);

                    // Output progress
                    Console.Write("Processing band {0} of {1} ({2:0.00} Hz - {3:0.00} Hz = {4:0.00} Hz)\r", bandidx, bands, range.First / filterscale, range.Second / filterscale, (range.Second - range.First) / filterscale);

                    /*
                     * Console.Out.WriteLine("-----");
                     * Console.Out.WriteLine("spectrum size: {0}", spectrum.Length);
                     * Console.Out.WriteLine("lowidx: {0:0.00} highidx: {1:0.00}", range.First, range.Second);
                     * Console.Out.WriteLine("(real)lowfreq: {0:0.00} (real)highfreq: {1:0.00}", range.First / filterscale, range.Second/filterscale);
                     * Console.Out.WriteLine("actual width: {0:0.00} hz", (range.Second-range.First)/filterscale);
                     * Console.Out.WriteLine("vertical values: {0:0.00}", (range.Second-range.First));
                     * Console.Out.WriteLine("crowd sample: {0:0.00}", (range.Second-range.First-1)*2);
                     * Console.Out.WriteLine("theoretically staci: {0:0.00} hz samplerate", 2*(range.Second-range.First)/filterscale);
                     * Console.Out.WriteLine("width: {0}", width);
                     */

                    // take the complex samples	specified by the range and copy into filterband
                    int filterbandLength = range.Second - range.First;
                    var filterband       = new Complex[filterbandLength];
                    //std::copy(spectrum.begin()+range.first,
                    //          spectrum.begin()+std::min(range.second, top_index),
                    //          filterband.begin());
                    int sourceIndexStart = range.First;
                    int sourceIndexEnd   = Math.Min(range.Second, top_index);
                    int length           = sourceIndexEnd - sourceIndexStart;
                    if (sourceIndexStart < sourceIndexEnd)
                    {
                        Array.Copy(spectrum, sourceIndexStart, filterband, 0, length);
                    }

                    // if the first range index is higher than the maximum index, we have reached the end
                    if (range.First > top_index)
                    {
                        break;
                    }
                    // if the second range index is higher than the maximum index, we are at the last band
                    if (range.Second > top_index)
                    {
                        //std::fill(filterband.begin()+top_index-range.first,
                        //          filterband.end(), Complex(0,0));
                        // not neccesary as c# already defaults the rest of the array to a Complex(0,0)
                    }

                    // windowing
                    ApplyWindow(ref filterband, range.First, filterscale);

                    // envelope detection
                    double[] envelope = SpectrogramUtils.GetEnvelope(ref filterband);

                    // resampling
                    envelope = SpectrogramUtils.Resample(envelope, width);

                    image_data.Add(envelope);
                }

                SpectrogramUtils.NormalizeImageCutoffNegative(ref image_data);

                return(MakeImage(image_data));
            }
        }
示例#12
0
        public double[] SynthetizeSine(Bitmap image, int samplerate)
        {
            using (new DebugTimer("Spectrogram: SynthetizeSine(Bitmap)"))
            {
                int samples  = image.Width * samplerate / pixpersec;
                var spectrum = new Complex[samples / 2 + 1];

                double filterscale = ((double)spectrum.Length * 2) / samplerate;

                Filterbank filterbank = Filterbank.GetFilterbank(frequency_axis, filterscale, basefreq, bandwidth, overlap);

                for (int bandidx = 0; bandidx < image.Height; ++bandidx)
                {
                    // TODO: support cancelling this process

                    OutputBandProgress(bandidx, image.Height);

                    double[] envelope = EnvelopeFromSpectrogram(image, bandidx);
                    // Find maximum number when all numbers are made positive.
                    //double max = envelope.Max((b) => Math.Abs(b));
                    //Console.WriteLine(max);

                    // random phase between +-pi
                    double phase = SpectrogramUtils.RandomDoubleMinus1ToPlus1() * Math.PI;

                    var bandsignal = new double[envelope.Length * 2];
                    for (int j = 0; j < 4; ++j)
                    {
                        double sine = Math.Cos(j * Math.PI / 2 + phase);
                        for (int i = j; i < bandsignal.Length; i += 4)
                        {
                            bandsignal[i] = envelope[i / 2] * sine;
                        }
                    }

                    var filterband = SpectrogramUtils.padded_FFT(ref bandsignal);

                    for (int i = 0; i < filterband.Length; ++i)
                    {
                        double x = (double)i / filterband.Length;

                        // normalized blackman window antiderivative
                        filterband[i] *= x - ((0.5 / (2.0 * Math.PI)) * Math.Sin(2.0 * Math.PI * x) + (0.08 / (4.0 * Math.PI)) * Math.Sin(4.0 * Math.PI * x) / 0.42);
                    }

                    //Console.Out.WriteLine("Spectrum size: {0}", spectrum.Length);
                    //std::cout << bandidx << ". filterband size: " << filterband.Length << "; start: " << filterbank->GetBand(bandidx).first <<"; end: " << filterbank->GetBand(bandidx).second << "\n";

                    double center = filterbank.GetCenter(bandidx);
                    double offset = Math.Max((double)0, center - filterband.Length / 2);

                    //Console.Out.WriteLine("Offset: {0} = {1} hz", offset, offset/filterscale);

                    for (int i = 0; i < filterband.Length; ++i)
                    {
                        int spectrumIndex = (int)(offset + i);
                        if (spectrumIndex > 0 && spectrumIndex < spectrum.Length)
                        {
                            spectrum[spectrumIndex] += filterband[i];
                        }
                    }
                }

                double[] @out = SpectrogramUtils.padded_IFFT(ref spectrum);

                Console.Out.WriteLine("Samples: {0} -> {1}", @out.Length, samples);

                SpectrogramUtils.NormalizeSignal(ref @out);
                return(@out);
            }
        }