/// <inheritdoc/> public override RecognizerResults Recognize( AudioRecording audioRecording, Config genericConfig, TimeSpan segmentStartOffset, Lazy <IndexCalculateResult[]> getSpectralIndexes, DirectoryInfo outputDirectory, int?imageWidth) { var configuration = (GenericRecognizerConfig)genericConfig; if (configuration.Profiles?.Count < 1) { throw new ConfigFileException( "The generic recognizer needs at least one profile set. 0 were found."); } int count = configuration.Profiles.Count; var message = $"Found {count} analysis profile(s): " + configuration.Profiles.Keys.Join(", "); Log.Info(message); var allResults = new RecognizerResults() { Events = new List <AcousticEvent>(), NewEvents = new List <EventCommon>(), Hits = null, ScoreTrack = null, Plots = new List <Plot>(), Sonogram = null, }; // Now process each of the profiles foreach (var(profileName, profileConfig) in configuration.Profiles) { Log.Info("Processing profile: " + profileName); //List<AcousticEvent> acousticEvents; List <EventCommon> spectralEvents; var plots = new List <Plot>(); SpectrogramStandard sonogram; Log.Debug($"Using the {profileName} algorithm... "); if (profileConfig is CommonParameters parameters) { if (profileConfig is BlobParameters || profileConfig is OscillationParameters || profileConfig is OnebinTrackParameters || profileConfig is HarmonicParameters || profileConfig is ForwardTrackParameters || profileConfig is UpwardTrackParameters || profileConfig is OneframeTrackParameters) { sonogram = new SpectrogramStandard(ParametersToSonogramConfig(parameters), audioRecording.WavReader); if (profileConfig is BlobParameters bp) { //get the array of intensity values minus intensity in side/buffer bands. //i.e. require silence in side-bands. Otherwise might simply be getting part of a broader band acoustic event. var decibelArray = SNR.CalculateFreqBandAvIntensityMinusBufferIntensity( sonogram.Data, bp.MinHertz.Value, bp.MaxHertz.Value, bp.BottomHertzBuffer.Value, bp.TopHertzBuffer.Value, sonogram.NyquistFrequency); // prepare plot of resultant blob decibel array. var plot = PreparePlot(decibelArray, $"{profileName} (Blob:db Intensity)", bp.DecibelThreshold.Value); plots.Add(plot); // iii: CONVERT blob decibel SCORES TO ACOUSTIC EVENTS. // Note: This method does NOT do prior smoothing of the dB array. var acEvents = AcousticEvent.GetEventsAroundMaxima( decibelArray, segmentStartOffset, bp.MinHertz.Value, bp.MaxHertz.Value, bp.DecibelThreshold.Value, TimeSpan.FromSeconds(bp.MinDuration.Value), TimeSpan.FromSeconds(bp.MaxDuration.Value), sonogram.FramesPerSecond, sonogram.FBinWidth); spectralEvents = acEvents.ConvertAcousticEventsToSpectralEvents(); } else if (profileConfig is OnebinTrackParameters wp) { //get the array of intensity values minus intensity in side/buffer bands. double[] decibelArray; (spectralEvents, decibelArray) = OnebinTrackAlgorithm.GetOnebinTracks( sonogram, wp, segmentStartOffset); var plot = PreparePlot(decibelArray, $"{profileName} (Whistle:dB Intensity)", wp.DecibelThreshold.Value); plots.Add(plot); } else if (profileConfig is ForwardTrackParameters tp) { double[] decibelArray; (spectralEvents, decibelArray) = ForwardTrackAlgorithm.GetForwardTracks( sonogram, tp, segmentStartOffset); var plot = PreparePlot(decibelArray, $"{profileName} (Chirps:dB Intensity)", tp.DecibelThreshold.Value); plots.Add(plot); } else if (profileConfig is OneframeTrackParameters cp) { double[] decibelArray; (spectralEvents, decibelArray) = OneframeTrackAlgorithm.GetOneFrameTracks( sonogram, cp, segmentStartOffset); var plot = PreparePlot(decibelArray, $"{profileName} (Clicks:dB Intensity)", cp.DecibelThreshold.Value); plots.Add(plot); } else if (profileConfig is UpwardTrackParameters vtp) { double[] decibelArray; (spectralEvents, decibelArray) = UpwardTrackAlgorithm.GetUpwardTracks( sonogram, vtp, segmentStartOffset); var plot = PreparePlot(decibelArray, $"{profileName} (VerticalTrack:dB Intensity)", vtp.DecibelThreshold.Value); plots.Add(plot); } else if (profileConfig is HarmonicParameters hp) { double[] decibelMaxArray; double[] harmonicIntensityScores; (spectralEvents, decibelMaxArray, harmonicIntensityScores) = HarmonicParameters.GetComponentsWithHarmonics( sonogram, hp.MinHertz.Value, hp.MaxHertz.Value, sonogram.NyquistFrequency, hp.DecibelThreshold.Value, hp.DctThreshold.Value, hp.MinDuration.Value, hp.MaxDuration.Value, hp.MinFormantGap.Value, hp.MaxFormantGap.Value, segmentStartOffset); var plot = PreparePlot(harmonicIntensityScores, $"{profileName} (Harmonics:dct intensity)", hp.DctThreshold.Value); plots.Add(plot); } else if (profileConfig is OscillationParameters op) { Oscillations2012.Execute( sonogram, op.MinHertz.Value, op.MaxHertz.Value, op.DctDuration, op.MinOscillationFrequency, op.MaxOscillationFrequency, op.DctThreshold, op.EventThreshold, op.MinDuration.Value, op.MaxDuration.Value, out var scores, out var oscillationEvents, out var hits, segmentStartOffset); spectralEvents = new List <EventCommon>(oscillationEvents); //plots.Add(new Plot($"{profileName} (:OscillationScore)", scores, op.EventThreshold)); var plot = PreparePlot(scores, $"{profileName} (:OscillationScore)", op.EventThreshold); plots.Add(plot); } else { throw new InvalidOperationException(); } } else { throw new InvalidOperationException(); } //iV add additional info to the acoustic events spectralEvents.ForEach(ae => { ae.FileName = audioRecording.BaseName; ae.Name = parameters.SpeciesName; ae.Profile = profileName; //ae.SegmentDurationSeconds = audioRecording.Duration.TotalSeconds; //ae.SegmentStartSeconds = segmentStartOffset.TotalSeconds; //ae.SetTimeAndFreqScales(sonogram.FrameStep, sonogram.FrameDuration, sonogram.FBinWidth); }); } else if (profileConfig is Aed.AedConfiguration ac) { var config = new SonogramConfig { NoiseReductionType = ac.NoiseReductionType, NoiseReductionParameter = ac.NoiseReductionParameter, }; sonogram = new SpectrogramStandard(config, audioRecording.WavReader); // GET THIS TO RETURN BLOB EVENTS. spectralEvents = Aed.CallAed(sonogram, ac, segmentStartOffset, audioRecording.Duration).ToList(); } else { throw new InvalidOperationException(); } // combine the results i.e. add the events list of call events. allResults.NewEvents.AddRange(spectralEvents); allResults.Plots.AddRange(plots); // effectively keeps only the *last* sonogram produced allResults.Sonogram = sonogram; Log.Debug($"{profileName} event count = {spectralEvents.Count}"); // DEBUG PURPOSES COMMENT NEXT LINE //SaveDebugSpectrogram(allResults, genericConfig, outputDirectory, "name"); } return(allResults); }
public void TestForwardTrackAlgorithm() { // Set up the recognizer parameters. var parameters = new ForwardTrackParameters() { MinHertz = 500, MaxHertz = 6000, MinDuration = 0.2, MaxDuration = 1.1, DecibelThreshold = 2.0, CombinePossibleHarmonics = false, HarmonicsStartDifference = TimeSpan.FromSeconds(0.2), HarmonicsHertzGap = 200, CombinePossibleSyllableSequence = false, SyllableStartDifference = 0.2, SyllableHertzGap = 300, }; //Set up the virtual recording. int samplerate = 22050; double signalDuration = 13.0; //seconds // set up the config for a virtual spectrogram. var sonoConfig = new SonogramConfig() { WindowSize = 512, WindowStep = 512, WindowOverlap = 0.0, // this must be set WindowFunction = WindowFunctions.HANNING.ToString(), NoiseReductionType = NoiseReductionType.Standard, NoiseReductionParameter = 0.0, Duration = TimeSpan.FromSeconds(signalDuration), SampleRate = samplerate, }; var spectrogram = this.CreateArtificialSpectrogramToTestTracksAndHarmonics(sonoConfig); //var image1 = SpectrogramTools.GetSonogramPlusCharts(spectrogram, null, null, null); //results.Sonogram.GetImage().Save(this.outputDirectory + "\\debug.png"); var segmentStartOffset = TimeSpan.Zero; var plots = new List <Plot>(); var(spectralEvents, dBArray) = ForwardTrackAlgorithm.GetForwardTracks( spectrogram, parameters, segmentStartOffset); // draw a plot of max decibels in each frame double decibelNormalizationMax = 5 * parameters.DecibelThreshold.Value; var dBThreshold = parameters.DecibelThreshold.Value / decibelNormalizationMax; var normalisedDecibelArray = DataTools.NormaliseInZeroOne(dBArray, 0, decibelNormalizationMax); var plot1 = new Plot("decibel max", normalisedDecibelArray, dBThreshold); plots.Add(plot1); var allResults = new RecognizerResults() { NewEvents = new List <EventCommon>(), Hits = null, ScoreTrack = null, Plots = new List <Plot>(), Sonogram = null, }; // combine the results i.e. add the events list of call events. allResults.NewEvents.AddRange(spectralEvents); allResults.Plots.AddRange(plots); // effectively keeps only the *last* sonogram produced allResults.Sonogram = spectrogram; // DEBUG PURPOSES COMMENT NEXT LINE this.SaveTestOutput( outputDirectory => GenericRecognizer.SaveDebugSpectrogram(allResults, null, outputDirectory, "ForwardTrack")); Assert.AreEqual(23, allResults.NewEvents.Count); var @event = (SpectralEvent)allResults.NewEvents[4]; Assert.AreEqual(2.0, @event.EventStartSeconds, 0.1); Assert.AreEqual(2.5, @event.EventEndSeconds, 0.1); Assert.AreEqual(1720, @event.LowFrequencyHertz); Assert.AreEqual(2107, @event.HighFrequencyHertz); @event = (SpectralEvent)allResults.NewEvents[11]; Assert.AreEqual(6.0, @event.EventStartSeconds, 0.1); Assert.AreEqual(6.5, @event.EventEndSeconds, 0.1); Assert.AreEqual(2150, @event.LowFrequencyHertz); Assert.AreEqual(2580, @event.HighFrequencyHertz); }