Exemple #1
0
        public override AnalysisResult2 Analyze <T>(AnalysisSettings analysisSettings, SegmentSettings <T> segmentSettings)
        {
            var recording = new AudioRecording(segmentSettings.SegmentAudioFile.FullName);

            // get indices configuration - extracted in BeforeAnalyze
            var acousticIndicesConfig = (RecognizerConfig)analysisSettings.Configuration;

            // get a lazily calculated indices function - if you never get the lazy value, the indices will never be calculated
            var lazyIndices = this.GetLazyIndices(
                recording,
                analysisSettings,
                segmentSettings,
                acousticIndicesConfig.HighResolutionIndices);

            // determine imageWidth for output images
            int imageWidth = (int)Math.Floor(
                recording.Duration.TotalSeconds
                / acousticIndicesConfig.HighResolutionIndices.IndexCalculationDuration);

            // execute actual analysis
            RecognizerResults results = this.Recognize(
                recording,
                analysisSettings.Configuration,
                segmentSettings.SegmentStartOffset,
                lazyIndices,
                segmentSettings.SegmentOutputDirectory,
                imageWidth);

            var analysisResults = new AnalysisResult2(analysisSettings, segmentSettings, recording.Duration);

            BaseSonogram sonogram = results.Sonogram;

            double[,] hits = results.Hits;
            var predictedEvents = results.GetAllEvents();

            // double check all the events have the right offset in case it was missed
            foreach (var predictedEvent in predictedEvents)
            {
                predictedEvent.SegmentStartSeconds    = segmentSettings.SegmentStartOffset.TotalSeconds;
                predictedEvent.SegmentDurationSeconds = recording.Duration.TotalSeconds;
            }

            analysisResults.Events = predictedEvents.ToArray();

            // compress high resolution indices - and save them.
            // IF they aren't used, empty values are returned.
            if (lazyIndices.IsValueCreated)
            {
                this.SummarizeHighResolutionIndices(
                    analysisResults,
                    lazyIndices.Value,
                    acousticIndicesConfig.HighResolutionIndices);
            }

            // write intermediate output if necessary
            if (analysisSettings.AnalysisDataSaveBehavior)
            {
                this.WriteEventsFile(segmentSettings.SegmentEventsFile, analysisResults.Events);
                analysisResults.EventsFile = segmentSettings.SegmentEventsFile;
            }

            if (analysisSettings.AnalysisDataSaveBehavior)
            {
                this.WriteSummaryIndicesFile(segmentSettings.SegmentSummaryIndicesFile, analysisResults.SummaryIndices);
            }

            if (analysisSettings.AnalysisDataSaveBehavior)
            {
                analysisResults.SpectraIndicesFiles =
                    this.WriteSpectrumIndicesFiles(
                        segmentSettings.SegmentSpectrumIndicesDirectory,
                        segmentSettings.Segment.SourceMetadata.Identifier,
                        analysisResults.SpectralIndices);
            }

            if (analysisSettings.AnalysisImageSaveBehavior.ShouldSave(analysisResults.Events.Length))
            {
                string       imagePath      = segmentSettings.SegmentImageFile.FullName;
                const double EventThreshold = 0.1;
                var          plots          = results.Plots ?? new List <Plot>();

                //TODO Remove this when we remove AcousticEvent.
                var convertedEvents = predictedEvents.Select(ec => ec is AcousticEvent ae ? EventConverters.ConvertAcousticEventToSpectralEvent(ae) : (EventCommon)ec).ToList();

                Image image = this.DrawSonogram(sonogram, hits, plots, convertedEvents, EventThreshold);
                image.Save(imagePath);
                analysisResults.ImageFile = segmentSettings.SegmentImageFile;

                // draw a fancy high res index image
                // IF indices aren't used, no image is drawn.
                if (lazyIndices.IsValueCreated)
                {
                    this.DrawLongDurationSpectrogram(
                        segmentSettings.SegmentOutputDirectory,
                        recording.BaseName,
                        results.ScoreTrack,
                        lazyIndices.Value,
                        acousticIndicesConfig.HighResolutionIndices);
                }
            }

            return(analysisResults);
        }
        public static (List <EventCommon> SpectralEvents, double[] AmplitudeArray, double[] HarmonicIntensityScores) GetComponentsWithHarmonics(
            SpectrogramStandard spectrogram,
            int minHz,
            int maxHz,
            int nyquist,
            double decibelThreshold,
            double dctThreshold,
            double minDuration,
            double maxDuration,
            int minFormantGap,
            int maxFormantGap,
            TimeSpan segmentStartOffset)
        {
            // Event threshold - Determines FP / FN trade-off for events.
            //double eventThreshold = 0.2;

            var sonogramData = spectrogram.Data;
            int frameCount   = sonogramData.GetLength(0);
            int binCount     = sonogramData.GetLength(1);

            double freqBinWidth = nyquist / (double)binCount;
            int    minBin       = (int)Math.Round(minHz / freqBinWidth);
            int    maxBin       = (int)Math.Round(maxHz / freqBinWidth);

            // extract the sub-band
            double[,] subMatrix = MatrixTools.Submatrix(spectrogram.Data, 0, minBin, frameCount - 1, maxBin);

            //ii: DETECT HARMONICS
            // now look for harmonics in search band using the Xcorrelation-DCT method.
            var results = CrossCorrelation.DetectHarmonicsInSpectrogramData(subMatrix, decibelThreshold);

            // set up score arrays
            double[] dBArray = results.Item1;
            double[] harmonicIntensityScores = results.Item2; //an array of formant intesnity
            int[]    maxIndexArray           = results.Item3;

            for (int r = 0; r < frameCount; r++)
            {
                if (harmonicIntensityScores[r] < dctThreshold)
                {
                    continue;
                }

                //ignore locations with incorrect formant gap
                int    maxId        = maxIndexArray[r];
                int    bandBinCount = maxBin - minBin + 1;
                double freqBinGap   = 2 * bandBinCount / (double)maxId;
                double formantGap   = freqBinGap * freqBinWidth;
                if (formantGap < minFormantGap || formantGap > maxFormantGap)
                {
                    harmonicIntensityScores[r] = 0.0;
                }
            }

            // smooth the harmonicIntensityScores array to allow for brief gaps.
            harmonicIntensityScores = DataTools.filterMovingAverageOdd(harmonicIntensityScores, 3);

            //extract the events based on length and threshhold.
            // Note: This method does NOT do prior smoothing of the score array.
            var harmonicEvents = AcousticEvent.ConvertScoreArray2Events(
                harmonicIntensityScores,
                minHz,
                maxHz,
                spectrogram.FramesPerSecond,
                spectrogram.FBinWidth,
                dctThreshold,
                minDuration,
                maxDuration,
                segmentStartOffset);

            var spectralEvents = new List <EventCommon>();

            // add in temporary names to the events
            // These can be altered later.
            foreach (var he in harmonicEvents)
            {
                var se = EventConverters.ConvertAcousticEventToSpectralEvent(he);
                spectralEvents.Add(se);
                se.Name = "Harmonics";
                //se.ComponentName = "Harmonics";
            }

            return(spectralEvents, dBArray, harmonicIntensityScores);
        }