// ################################# 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> /// Initializes a new instance of the <see cref="AmplitudeSpectrogram"/> class. /// </summary> public AmplitudeSpectrogram(SpectrogramSettings config, WavReader wav) { this.Configuration = config; this.Attributes = new SpectrogramAttributes(); double minDuration = 1.0; if (wav.Time.TotalSeconds < minDuration) { LoggedConsole.WriteLine("Signal must at least {0} seconds long to produce a sonogram!", minDuration); return; } //set attributes for the current recording and spectrogram type this.Attributes.SampleRate = wav.SampleRate; this.Attributes.Duration = wav.Time; this.Attributes.NyquistFrequency = wav.SampleRate / 2; this.Attributes.Duration = wav.Time; this.Attributes.MaxAmplitude = wav.CalculateMaximumAmplitude(); this.Attributes.FrameDuration = TimeSpan.FromSeconds(this.Configuration.WindowSize / (double)wav.SampleRate); var recording = new AudioRecording(wav); var fftdata = DSP_Frames.ExtractEnvelopeAndFfts( recording, config.WindowSize, config.WindowOverlap, this.Configuration.WindowFunction); // now recover required data //epsilon is a signal dependent minimum amplitude value to prevent possible subsequent log of zero value. this.Attributes.Epsilon = fftdata.Epsilon; this.Attributes.WindowPower = fftdata.WindowPower; this.Attributes.FrameCount = fftdata.FrameCount; this.Data = fftdata.AmplitudeSpectrogram; // IF REQUIRED CONVERT TO MEL SCALE if (this.Configuration.DoMelScale) { // this mel scale conversion uses the "Greg integral" ! this.Data = MFCCStuff.MelFilterBank(this.Data, this.Configuration.MelBinCount, this.Attributes.NyquistFrequency, 0, this.Attributes.NyquistFrequency); } }
/// <summary> /// Initializes a new instance of the <see cref="EnergySpectrogram"/> class. /// Use this constructor when you have config and audio objects /// </summary> public EnergySpectrogram(SpectrogramSettings config, WavReader wav) : this(new AmplitudeSpectrogram(config, wav)) { }