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)); } }
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); } }