public static Image FrameSonogram(Image image, Image titleBar, TimeSpan minuteOffset, TimeSpan xAxisTicInterval, TimeSpan xAxisPixelDuration, TimeSpan labelInterval, int nyquist, int herzInterval) { double secondsDuration = xAxisPixelDuration.TotalSeconds * image.Width; var fullDuration = TimeSpan.FromSeconds(secondsDuration); // init frequency scale int frameSize = image.Height; var freqScale = new FrequencyScale(nyquist, frameSize, herzInterval); SpectrogramTools.DrawGridLinesOnImage((Bitmap)image, minuteOffset, fullDuration, xAxisTicInterval, freqScale); int imageWidth = image.Width; int trackHeight = 20; int imageHt = image.Height + trackHeight + trackHeight + trackHeight; var timeBmp = DrawTimeTrack(minuteOffset, xAxisPixelDuration, xAxisTicInterval, labelInterval, imageWidth, trackHeight, "Seconds"); var compositeBmp = new Bitmap(imageWidth, imageHt); //get canvas for entire image var gr = Graphics.FromImage(compositeBmp); gr.Clear(Color.Black); int offset = 0; gr.DrawImage(titleBar, 0, offset); //draw in the top time scale offset += timeBmp.Height; gr.DrawImage(timeBmp, 0, offset); //draw offset += titleBar.Height; gr.DrawImage(image, 0, offset); //draw offset += image.Height; gr.DrawImage(timeBmp, 0, offset); //draw return(compositeBmp); }
public SpectrogramCepstral(AmplitudeSonogram sg, int minHz, int maxHz) : this(sg) { this.DecibelsPerFrame = sg.DecibelsPerFrame; this.DecibelsNormalised = sg.DecibelsNormalised; this.Duration = sg.Duration; this.FrameCount = sg.FrameCount; this.DecibelReference = sg.DecibelReference; this.MaxAmplitude = sg.MaxAmplitude; this.SampleRate = sg.SampleRate; this.SigState = sg.SigState; this.SnrData = sg.SnrData; // subband highlighting no longer available //this.subBandMinHz = minHz; //this.subBandMaxHz = maxHz; //double[] noise_subband = BaseSonogram.ExtractModalNoiseSubband(this.SnrData.ModalNoiseProfile, minHz, maxHz, sg.doMelScale, // sonogram.Configuration.FreqBinCount, sonogram.FBinWidth); this.Data = SpectrogramTools.ExtractFreqSubband(sg.Data, minHz, maxHz, this.Configuration.DoMelScale, sg.Configuration.FreqBinCount, sg.FBinWidth); // NO LONGER DO THIS >>>> CalculateSubbandSNR(this.Data); this.Make(this.Data); //converts amplitude matrix to cepstral sonogram }
/// <summary> /// This method assumes that the height of the passed sonogram image is half of the original frame size. /// This assumption allows the frequency scale grid lines to be placed at the correct intervals. /// </summary> public static Image FrameSonogram( Image sonogramImage, Image titleBar, TimeSpan minuteOffset, TimeSpan xAxisTicInterval, TimeSpan xAxisPixelDuration, TimeSpan labelInterval, int nyquist, int hertzInterval) { double secondsDuration = xAxisPixelDuration.TotalSeconds * sonogramImage.Width; var fullDuration = TimeSpan.FromSeconds(secondsDuration); // init frequency scale int frameSize = sonogramImage.Height * 2; var freqScale = new FrequencyScale(nyquist, frameSize, hertzInterval); SpectrogramTools.DrawGridLinesOnImage((Bitmap)sonogramImage, minuteOffset, fullDuration, xAxisTicInterval, freqScale); int imageWidth = sonogramImage.Width; var timeBmp = ImageTrack.DrawShortTimeTrack(minuteOffset, xAxisPixelDuration, xAxisTicInterval, labelInterval, imageWidth, "Seconds"); Image[] imageArray = { titleBar, timeBmp, sonogramImage, timeBmp }; return(ImageTools.CombineImagesVertically(imageArray)); }
/// <summary> /// Use this method to average a decibel spectrogram /// </summary> public static double[] CalculateAvgDecibelSpectrumFromSpectrogram(double[,] spectrogram) { int frameCount = spectrogram.GetLength(0); int freqBinCount = spectrogram.GetLength(1); double[] avgSpectrum = new double[freqBinCount]; for (int j = 0; j < freqBinCount; j++) { var freqBin = MatrixTools.GetColumn(spectrogram, j); double av = SpectrogramTools.AverageAnArrayOfDecibelValues(freqBin); avgSpectrum[j] = av; } return(avgSpectrum); }
/// <summary> /// The data passed to this method must be the Spectral sonogram. /// </summary> public static Tuple <double[, ], double[]> GetCepstrogram(double[,] data, int minHz, int maxHz, int freqBinCount, double freqBinWidth, bool doMelScale, int ccCount) { ImageTools.DrawMatrix(data, @"C:\SensorNetworks\Output\MFCC_LewinsRail\tempImage1.jpg", false); double[,] m = SpectrogramTools.ExtractFreqSubband(data, minHz, maxHz, doMelScale, freqBinCount, freqBinWidth); ImageTools.DrawMatrix(m, @"C:\SensorNetworks\Output\MFCC_LewinsRail\tempImage2.jpg", false); //DO NOT DO NOISE REDUCTION BECAUSE ALREADY DONE //double[] modalNoise = SNR.CalculateModalNoise(m, 7); //calculate modal noise profile and smooth //m = SNR.NoiseReduce_Standard(m, modalNoise); //m = SNR.NoiseReduce_FixedRange(m, this.Configuration.DynamicRange); m = MFCCStuff.Cepstra(m, ccCount); m = DataTools.normalise(m); ImageTools.DrawMatrix(m, @"C:\SensorNetworks\Output\MFCC_LewinsRail\tempImage3.jpg", false); return(Tuple.Create(m, (double[])null)); }
// ################################# STATIC METHODS BELOW HERE ############################### public static Image DrawSpectrogramAnnotated(double[,] data, SpectrogramSettings config, SpectrogramAttributes attributes) { // normalise the data between 0 and 95th percentiles int binCount = 100; double min; double max; DataTools.MinMax(data, out min, out max); double binWidth = (max - min) / binCount; var histogram = Histogram.Histo(data, binCount, min, max, binWidth); int percentile = 95; int binId = Histogram.GetPercentileBin(histogram, percentile); double upperBound = min + (binId * percentile); var normedMatrix = MatrixTools.NormaliseInZeroOne(data, min, upperBound); /* * int minPercentile = 5; * int minBinId = Histogram.GetPercentileBin(histogram, minPercentile); * double lowerBound = min + (minBinId * minPercentile); * int maxPercentile = 95; * int maxBinId = Histogram.GetPercentileBin(histogram, maxPercentile); * double upperBound = min + (maxBinId * maxPercentile); * var normedMatrix = MatrixTools.NormaliseInZeroOne(data, lowerBound, upperBound); */ int nyquist = attributes.NyquistFrequency; int frameSize = config.WindowSize; // assuming linear frequency scale int finalBinCount = frameSize / 2; var scaleType = FreqScaleType.Linear; // if doing mel scale then if (config.DoMelScale) { finalBinCount = 256; //128; //512; // 256; // 100; // 40; // 200; // scaleType = FreqScaleType.Mel; } var freqScale = new FrequencyScale(scaleType, nyquist, frameSize, finalBinCount, hertzGridInterval: 1000); var image = SpectrogramTools.GetImage(normedMatrix, nyquist, config.DoMelScale); var annotatedImage = SpectrogramTools.GetImageFullyAnnotated(image, config.SourceFileName + ": " + scaleType.ToString(), freqScale.GridLineLocations, attributes.Duration); return(annotatedImage); }
/// <summary> /// Returns a Spectrogram and Cepstrogram from the passed recording. These are NOT noise reduced. /// however, tuple also returns the modal noise and sub-band modal noise. /// </summary> public static Tuple <SpectrogramStandard, SpectrogramCepstral, double[], double[]> GetAllSonograms(AudioRecording recording, SonogramConfig sonoConfig, int minHz, int maxHz) { int sr = recording.SampleRate; bool doMelScale = sonoConfig.DoMelScale; int ccCount = sonoConfig.mfccConfig.CcCount; bool includeDelta = sonoConfig.mfccConfig.IncludeDelta; bool includeDoubleDelta = sonoConfig.mfccConfig.IncludeDoubleDelta; sonoConfig.SourceFName = recording.BaseName; var basegram = new AmplitudeSonogram(sonoConfig, recording.WavReader); var sonogram = new SpectrogramStandard(basegram); //spectrogram has dim[N,257] Log.WriteLine("Signal: Duration={0}, Sample Rate={1}", sonogram.Duration, sr); Log.WriteLine( $"Frames: Size={0}, Count={1}, Duration={2:f1}ms, Overlap={5:f0}%, Offset={3:f1}ms, Frames/s={4:f1}", sonogram.Configuration.WindowSize, sonogram.FrameCount, sonogram.FrameDuration * 1000, sonogram.FrameStep * 1000, sonogram.FramesPerSecond, sonoConfig.WindowOverlap * 100); int binCount = (int)(maxHz / sonogram.FBinWidth) - (int)(minHz / sonogram.FBinWidth) + 1; Log.WriteLine("Freqs : {0} Hz - {1} Hz. (Freq bin count = {2})", minHz, maxHz, binCount); Log.WriteLine("MFCCs : doMelScale=" + doMelScale + "; ccCount=" + ccCount + "; includeDelta=" + includeDelta + "; includeDoubleDelta=" + includeDoubleDelta); //CALCULATE MODAL NOISE PROFILE - USER MAY REQUIRE IT FOR NOISE REDUCTION double[] modalNoise = sonogram.SnrData.ModalNoiseProfile; //extract sub-band modal noise profile double[] noiseSubband = SpectrogramTools.ExtractModalNoiseSubband(modalNoise, minHz, maxHz, doMelScale, sonogram.NyquistFrequency, sonogram.FBinWidth); // CALCULATE CEPSTRO-GRAM. //cepstrogram has dim[N,13] var cepstrogram = new SpectrogramCepstral(basegram, minHz, maxHz); var tuple = Tuple.Create(sonogram, cepstrogram, modalNoise, noiseSubband); return(tuple); }