diff --git a/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs b/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs index dfcd0fd55..2dd981037 100644 --- a/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs +++ b/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs @@ -47,6 +47,117 @@ public override void Draw(IImageProcessingContext graphics, EventRenderingOption this.DrawEventLabel(graphics, options); } + /// + /// Converts the Oscillation Detector score array to a list of Oscillation Events. + /// + /// min threshold. + /// max threshold. + /// lower freq bound of the acoustic event. + /// upper freq bound of the acoustic event. + /// the minimum oscillations per second. + /// the maximum oscillations per second. + /// the array of OD scores. + /// threshold. + /// time offset. + public static List ConvertOscillationScores2Events( + SpectrogramStandard spectrogram, + double minDurationThreshold, + double maxDurationThreshold, + int minHz, + int maxHz, + double? minOscilFrequency, + double? maxOscilFrequency, + double[] oscilScores, + double scoreThreshold, + TimeSpan segmentStartOffset) + { + // The name of source file + string fileName = spectrogram.Configuration.SourceFName; + double framesPerSec = spectrogram.FramesPerSecond; + double freqBinWidth = spectrogram.FBinWidth; + int count = oscilScores.Length; + + // get the bin bounds of the frequency band of interest. + int minBin = (int)(minHz / freqBinWidth); + int maxBin = (int)(maxHz / freqBinWidth); + + // get the oeriodicity bounds for the frequency band of interest. + double? minPeriodicity = 1 / maxOscilFrequency; + double? maxPeriodicity = 1 / minOscilFrequency; + + var events = new List(); + bool isHit = false; + double frameOffset = 1 / framesPerSec; + int startFrame = 0; + + //pass over all frames + for (int i = 0; i < count; i++) + { + if (isHit == false && oscilScores[i] >= scoreThreshold) + { + //start of an event + isHit = true; + startFrame = i; + } + else //check for the end of an event + if (isHit && (oscilScores[i] < scoreThreshold || i == count - 1)) + { + isHit = false; + double duration = (i - startFrame + 1) * frameOffset; + if (duration < minDurationThreshold || duration > maxDurationThreshold) + { + //skip events with duration outside the required bounds + continue; + } + + // This is end of an event, so initialise it + // First trim the event because oscillation events spill over the edges of the true event due to use of the DCT. + (int trueStartFrame, int trueEndFrame, double framePeriodicity) = OscillationEvent.TrimEvent(spectrogram, startFrame, minBin, i, maxBin); + double trueStartTime = trueStartFrame * frameOffset; + double trueEndTime = trueEndFrame * frameOffset; + int trueFrameLength = trueEndFrame - trueStartFrame + 1; + + // Determine if the periodicity is within the required bounds. + var periodicity = framePeriodicity * frameOffset; + if (periodicity < minPeriodicity || periodicity > maxPeriodicity) + { + //skip events with periodicity outside the required bounds + continue; + } + + //obtain average score. + double sum = 0.0; + for (int n = trueStartFrame; n <= trueEndFrame; n++) + { + sum += oscilScores[n]; + } + + double score = sum / trueFrameLength; + + var ev = new OscillationEvent() + { + Name = "Oscillation", + SegmentStartSeconds = segmentStartOffset.TotalSeconds, + ResultStartSeconds = segmentStartOffset.TotalSeconds + trueStartTime, + EventStartSeconds = segmentStartOffset.TotalSeconds + trueStartTime, + EventEndSeconds = segmentStartOffset.TotalSeconds + trueEndTime, + LowFrequencyHertz = minHz, + HighFrequencyHertz = maxHz, + Periodicity = framePeriodicity * frameOffset, + Score = score, + FileName = fileName, + }; + + //########################################################################################## + //ev.Score2 = av / (i - startFrame + 1); + //ev.Intensity = (int)ev.Score2; // store this info for later inclusion in csv file as Event Intensity + events.Add(ev); + } + } + + return events; + } + /// /// Extracts an event from a spectrogram given its bounds. /// Then trims the event because oscillation events do not typically start where the DCT places them.