diff --git a/src/AnalysisConfigFiles/RecognizerConfigFiles/Towsey.NinoxBoobook.yml b/src/AnalysisConfigFiles/RecognizerConfigFiles/Towsey.NinoxBoobook.yml
new file mode 100644
index 000000000..fd4da317c
--- /dev/null
+++ b/src/AnalysisConfigFiles/RecognizerConfigFiles/Towsey.NinoxBoobook.yml
@@ -0,0 +1,58 @@
+---
+
+# Resample rate must be 2 X the desired Nyquist
+#ResampleRate: 22050
+#ResampleRate: 16000
+# SegmentDuration: units=seconds;
+SegmentDuration: 60
+# SegmentOverlap: units=seconds;
+SegmentOverlap: 0
+
+# Each of these profiles will be analyzed
+Profiles:
+ PeakTrackSyllable: !ForwardTrackParameters
+ ComponentName: RidgeTrack
+ SpeciesName: NinoxBoobook
+ FrameSize: 1024
+ FrameStep: 256
+ WindowFunction: HANNING
+ BgNoiseThreshold: 0.0
+ # min and max of the freq band to search
+ MinHertz: 300
+ MaxHertz: 1000
+ MinDuration: 0.15
+ MaxDuration: 0.5
+ DecibelThreshold: 6.0
+
+#Combine each pair of Boobook syllables as one event
+#CombineProximalSimilarEvents: false
+CombinePossibleSyllableSequence: true
+SyllableStartDifference: 0.6
+SyllableHertzGap: 200
+
+#CombineOverlappedEvents: false
+# Common settings
+#Standard: &STANDARD
+#EventThreshold: 0.2
+#BgNoiseThreshold: 3.0
+
+# This notation means the a profile has all of the settings that the Standard profile has,
+# however, the DctDuration parameter has been overridden.
+# <<: *STANDARD
+# DctDuration: 0.3
+
+# Available options (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
+SaveIntermediateWavFiles: Never
+SaveIntermediateCsvFiles: false
+# Available options (case-sensitive): [False/Never | True/Always | WhenEventsDetected]
+# "True" is useful when debugging but "WhenEventsDetected" is required for operational use.
+SaveSonogramImages: True
+#SaveSonogramImages: WhenEventsDetected
+# DisplayCsvImage is obsolete - ensure it remains set to: false
+DisplayCsvImage: false
+## End section for AnalyzeLongRecording
+
+# Other config files to reference
+
+HighResolutionIndicesConfig: "../Towsey.Acoustic.HiResIndicesForRecognisers.yml"
+...
\ No newline at end of file
diff --git a/src/AnalysisPrograms/Recognizers/Birds/NinoxBoobook.cs b/src/AnalysisPrograms/Recognizers/Birds/NinoxBoobook.cs
index e27efbd72..7af75b689 100644
--- a/src/AnalysisPrograms/Recognizers/Birds/NinoxBoobook.cs
+++ b/src/AnalysisPrograms/Recognizers/Birds/NinoxBoobook.cs
@@ -2,14 +2,6 @@
// All code in this file and all associated files are the copyright and property of the QUT Ecoacoustics Research Group (formerly MQUTeR, and formerly QUT Bioacoustics Research Group).
//
-///
-/// A recognizer for the Australian Boobook Owl, /// https://en.wikipedia.org/wiki/Australian_boobook .
-/// Eight subspecies of the Australian boobook are recognized,
-/// with three further subspecies being reclassified as separate species in 2019 due to their distinctive calls and genetics.
-/// THis recognizer has been trained on good quality calls from the Gympie recordings obtained by Yvonne Phillips.
-/// The recognizer has also been run across several recordings of Boobook from NZ (recordings obtained from Stuart Parsons.
-/// The NZ Boobook calls were of poor quality (distant and echo) and were 200 Hertz higher and performance was not good.
-///
namespace AnalysisPrograms.Recognizers
{
using System;
@@ -17,10 +9,13 @@ namespace AnalysisPrograms.Recognizers
using System.IO;
using System.Linq;
using System.Reflection;
+ using System.Runtime.CompilerServices;
using Acoustics.Shared.ConfigFile;
+ using AnalysisBase;
using AnalysisPrograms.Recognizers.Base;
using AudioAnalysisTools;
using AudioAnalysisTools.DSP;
+ using AudioAnalysisTools.Events;
using AudioAnalysisTools.Events.Types;
using AudioAnalysisTools.Indices;
using AudioAnalysisTools.StandardSpectrograms;
@@ -28,8 +23,17 @@ namespace AnalysisPrograms.Recognizers
using log4net;
using SixLabors.ImageSharp;
using TowseyLibrary;
+ using static AnalysisPrograms.Recognizers.GenericRecognizer;
using Path = System.IO.Path;
+ ///
+ /// A recognizer for the Australian Boobook Owl, /// https://en.wikipedia.org/wiki/Australian_boobook .
+ /// Eight subspecies of the Australian boobook are recognized,
+ /// with three further subspecies being reclassified as separate species in 2019 due to their distinctive calls and genetics.
+ /// THis recognizer has been trained on good quality calls from the Gympie recordings obtained by Yvonne Phillips.
+ /// The recognizer has also been run across several recordings of Boobook from NZ (recordings obtained from Stuart Parsons.
+ /// The NZ Boobook calls were of poor quality (distant and echo) and were 200 Hertz higher and performance was not good.
+ ///
internal class NinoxBoobook : RecognizerBase
{
private static readonly ILog BoobookLog = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -40,113 +44,108 @@ internal class NinoxBoobook : RecognizerBase
public override string Description => "[ALPHA] Detects acoustic events for the Australian Boobook owl.";
- /*
- ///
- /// Summarize your results. This method is invoked exactly once per original file.
- ///
- public override void SummariseResults(
- AnalysisSettings settings,
- FileSegment inputFileSegment,
- EventBase[] events,
- SummaryIndexBase[] indices,
- SpectralIndexBase[] spectralIndices,
- AnalysisResult2[] results)
+ public override AnalyzerConfig ParseConfig(FileInfo file)
{
- // No operation - do nothing. Feel free to add your own logic.
- base.SummariseResults(settings, inputFileSegment, events, indices, spectralIndices, results);
+ RuntimeHelpers.RunClassConstructor(typeof(NinoxBoobookConfig).TypeHandle);
+ var config = ConfigFile.Deserialize(file);
+
+ // validation of configs can be done here
+ GenericRecognizer.ValidateProfileTagsMatchAlgorithms(config.Profiles, file);
+
+ // This call sets a restriction so that only one generic algorithm is used.
+ // CHANGE this to accept multiple generic algorithms as required.
+ //if (result.Profiles.SingleOrDefault() is ForwardTrackParameters)
+ if (config.Profiles?.Count == 1 && config.Profiles.First().Value is ForwardTrackParameters)
+ {
+ return config;
+ }
+
+ throw new ConfigFileException("NinoxBoobook expects one and only one ForwardTrack algorithm.", file);
}
- */
///
/// This method is called once per segment (typically one-minute segments).
///
/// one minute of audio recording.
- /// config file that contains parameters used by all profiles.
+ /// config file that contains parameters used by all profiles.
/// when recording starts.
/// not sure what this is.
/// where the recognizer results can be found.
/// assuming ????.
/// recognizer results.
- public override RecognizerResults Recognize(AudioRecording audioRecording, Config genericConfig, TimeSpan segmentStartOffset, Lazy getSpectralIndexes, DirectoryInfo outputDirectory, int? imageWidth)
+ public override RecognizerResults Recognize(
+ AudioRecording audioRecording,
+ Config config,
+ TimeSpan segmentStartOffset,
+ Lazy getSpectralIndexes,
+ DirectoryInfo outputDirectory,
+ int? imageWidth)
{
+ //class NinoxBoobookConfig is define at bottom of this file.
+ var genericConfig = (NinoxBoobookConfig)config;
var recognizer = new GenericRecognizer();
- var config = recognizer.ParseConfig(FileInfo file);
- /*
- string[] profileNames = null;
- if (ConfigFile.HasProfiles(genericConfig))
- {
- profileNames = ConfigFile.GetProfileNames(genericConfig);
- int count = profileNames.Length;
- var message = $"Found {count} config profile(s): ";
- foreach (string s in profileNames)
- {
- message = message + (s + ", ");
- }
-
- BoobookLog.Debug(message);
- }
- else
- {
- BoobookLog.Warn("No configuration profiles found.");
- }
+ RecognizerResults combinedResults = recognizer.Recognize(
+ audioRecording,
+ genericConfig,
+ segmentStartOffset,
+ getSpectralIndexes,
+ outputDirectory,
+ imageWidth);
+
+ // DO POST-PROCESSING of EVENTS
- var combinedResults = new RecognizerResults();
+ // Convert events to spectral events for possible combining.
+ // Combine overlapping events. If the dB threshold is set low, may get lots of little events.
+ //
+ var events = combinedResults.NewEvents;
+ var spectralEvents = events.Select(x => (SpectralEvent)x).ToList();
+ var newEvents = CompositeEvent.CombineOverlappingEvents(spectralEvents);
- foreach (var profileName in profileNames)
+ if (genericConfig.CombinePossibleSyllableSequence)
{
- var results = new RecognizerResults();
-
- if (ConfigFile.TryGetProfile(genericConfig, profileName, out var profile))
- {
- results = recognizer.(audioRecording, genericConfig, "Territorial", segmentStartOffset);
- BoobookLog.Debug("Boobook event count = " + results.Events.Count);
- }
- else
- {
- BoobookLog.Warn($"Could not access {profileName} configuration parameters");
- }
-
- // combine the results i.e. add wing-beat events to the list of territorial call events.
- //NOTE: The returned territorialResults and wingbeatResults will never be null.
- combinedResults.Events.AddRange(results.Events);
- combinedResults.Plots.AddRange(results.Plots);
+ // convert events to spectral events for possible combining.
+ //var spectralEvents = events.Select(x => (SpectralEvent)x).ToList();
+ spectralEvents = newEvents.Cast().ToList();
+ var startDiff = genericConfig.SyllableStartDifference;
+ var hertzDiff = genericConfig.SyllableHertzGap;
+ newEvents = CompositeEvent.CombineSimilarProximalEvents(spectralEvents, TimeSpan.FromSeconds(startDiff), (int)hertzDiff);
}
+ combinedResults.NewEvents = newEvents;
+
//UNCOMMENT following line if you want special debug spectrogram, i.e. with special plots.
// NOTE: Standard spectrograms are produced by setting SaveSonogramImages: "True" or "WhenEventsDetected" in config file.
- //SaveDebugSpectrogram(territorialResults, genericConfig, outputDirectory, audioRecording.BaseName);
- */
+ //GenericRecognizer.SaveDebugSpectrogram(territorialResults, genericConfig, outputDirectory, audioRecording.BaseName);
return combinedResults;
}
+ /*
///
- /// returns a base sonogram type from which spectrogram images are prepared.
+ /// Summarize your results. This method is invoked exactly once per original file.
///
- internal static BaseSonogram GetSonogram(Config configuration, AudioRecording audioRecording)
+ public override void SummariseResults(
+ AnalysisSettings settings,
+ FileSegment inputFileSegment,
+ EventBase[] events,
+ SummaryIndexBase[] indices,
+ SpectralIndexBase[] spectralIndices,
+ AnalysisResult2[] results)
{
- var sonoConfig = new SonogramConfig
- {
- WindowSize = 512,
- NoiseReductionType = NoiseReductionType.Standard,
- NoiseReductionParameter = configuration.GetDoubleOrNull(AnalysisKeys.NoiseBgThreshold) ?? 0.0,
- WindowOverlap = 0.0,
- };
-
- // now construct the standard decibel spectrogram WITH noise removal
- // get frame parameters for the analysis
- var sonogram = (BaseSonogram)new SpectrogramStandard(sonoConfig, audioRecording.WavReader);
- return sonogram;
+ // No operation - do nothing. Feel free to add your own logic.
+ base.SummariseResults(settings, inputFileSegment, events, indices, spectralIndices, results);
}
+ */
- ///
- /// THis method can be modified if want to do something non-standard with the output spectrogram.
- ///
- internal static void SaveDebugSpectrogram(RecognizerResults results, Config genericConfig, DirectoryInfo outputDirectory, string baseName)
+ /// />
+ public class NinoxBoobookConfig : GenericRecognizerConfig, INamedProfiles