/// <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); }