/// <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);
            }
        }
Пример #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BaseSonogram"/> class.
        /// BASE CONSTRUCTOR
        /// This constructor contains all steps required to prepare the amplitude spectrogram.
        /// The third boolean parameter is simply a place-filler to ensure a different Constructor signature.
        /// from the principle Constructor which follows.
        /// </summary>
        /// <param name="config">config file to use.</param>
        /// <param name="wav">wav.</param>
        /// <param name="dummy">filler boolean. Calculate in method.</param>
        public BaseSonogram(SonogramConfig config, WavReader wav, bool dummy)
            : this(config)
        {
            // As of 28 March 2017 drop capability to get sub-band of spectrogram because was not being used.
            // can be recovered later if desired.
            //bool doExtractSubband = this.SubBandMinHz > 0 || this.SubBandMaxHz < this.NyquistFrequency;

            this.Duration = wav.Time;
            double minDuration = 0.2;
            if (this.Duration.TotalSeconds < minDuration)
            {
                LoggedConsole.WriteLine("Signal must at least {0} seconds long to produce a sonogram!", minDuration);
                return;
            }

            //set config params to the current recording
            this.SampleRate               = wav.SampleRate;
            this.Configuration.Duration   = wav.Time;
            this.Configuration.SampleRate = wav.SampleRate; //also set the Nyquist
            this.MaxAmplitude             = wav.CalculateMaximumAmplitude();

            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.Configuration.epsilon     = fftData.Epsilon;
            this.Configuration.WindowPower = fftData.WindowPower;
            this.FrameCount       = fftData.FrameCount;
            this.DecibelsPerFrame = fftData.FrameDecibels;

            //init normalised signal energy array but do nothing with it. This has to be done from outside
            this.DecibelsNormalised = new double[this.FrameCount];
            this.Data = fftData.AmplitudeSpectrogram;

            // ENERGY PER FRAME and NORMALISED dB PER FRAME AND SNR
            // currently DoSnr = true by default
            if (config.DoSnr)
            {
                // If the FractionOfHighEnergyFrames PRIOR to noise removal exceeds SNR.FractionalBoundForMode,
                // then Lamel's noise removal algorithm may not work well.
                if (fftData.FractionOfHighEnergyFrames > SNR.FractionalBoundForMode)
                {
                    Log.WriteIfVerbose("\nWARNING ##############");
                    Log.WriteIfVerbose(
                        "\t############### BaseSonogram(): This is a high energy recording. Percent of high energy frames = {0:f0} > {1:f0}%",
                        fftData.FractionOfHighEnergyFrames * 100,
                        SNR.FractionalBoundForMode * 100);
                    Log.WriteIfVerbose("\t############### Noise reduction algorithm may not work well in this instance!\n");
                }

                //AUDIO SEGMENTATION/END POINT DETECTION - based on Lamel et al
                // Setting segmentation/endpoint detection parameters is broken as of September 2014.
                // The next line is a hack replacement
                EndpointDetectionConfiguration.SetDefaultSegmentationConfig();
                this.SigState = EndpointDetectionConfiguration.DetermineVocalisationEndpoints(this.DecibelsPerFrame, this.FrameStep);
            }

            /* AS OF 30 MARCH 2017, NO LONGER IMPLEMENT SUB-BAND THINGS, because not being used for years.
             * // EXTRACT REQUIRED FREQUENCY BAND
             * if (doExtractSubband)
             * {
             *  this.Data = SpectrogramTools.ExtractFreqSubband(
             *      this.Data,
             *      this.subBandMinHz,
             *      this.subBandMaxHz,
             *      this.Configuration.DoMelScale,
             *      this.Configuration.FreqBinCount,
             *      this.FBinWidth);
             *  this.CalculateSubbandSNR(this.Data);
             * }
             */
        }