diff --git a/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs b/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs index a70a05f46..dfcd0fd55 100644 --- a/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs +++ b/src/AudioAnalysisTools/Events/Types/OscillationEvent.cs @@ -6,6 +6,7 @@ namespace AudioAnalysisTools { using System; using System.Collections.Generic; + using System.Linq; using AudioAnalysisTools.Events; using AudioAnalysisTools.Events.Drawing; using AudioAnalysisTools.StandardSpectrograms; @@ -26,6 +27,11 @@ public OscillationEvent() /// public double Periodicity { get; set; } + /// + /// Gets the oascillation rate. This is calculated from the Periodicity. Cannot be set directly. + /// + public double OscillationRate => 1 / this.Periodicity; + /// /// Draws a border around this oscillation event. /// @@ -44,18 +50,21 @@ public override void Draw(IImageProcessingContext graphics, EventRenderingOption /// /// 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. - /// It a;sp returns the periodicity of the oscillation event. + /// It also returns the periodicity of the oscillation event. /// public static (int EventStart, int EventEnd, double FramePeriod) TrimEvent(SpectrogramStandard spectrogram, int startFrame, int minBin, int endFrame, int maxBin) { - //obtain the oscillation event's periodicity. //extract the relevant portion of the spectrogram. var eventMatrix = MatrixTools.Submatrix(spectrogram.Data, startFrame, minBin, endFrame, maxBin); + + // Caclulate a normalised vector of timeframe average amplitudes. var frameAverages = MatrixTools.GetRowAverages(eventMatrix); + var meanValue = frameAverages.Average(); + frameAverages = DataTools.SubtractValueAndTruncateToZero(frameAverages, meanValue); frameAverages = DataTools.normalise(frameAverages); - double threshold = 0.25; + double threshold = 0.33; - // find the true start frame + // find a potentially more accurate start frame int startFrameOffset = 0; for (int frame = 1; frame < frameAverages.Length; frame++) { @@ -66,8 +75,9 @@ public static (int EventStart, int EventEnd, double FramePeriod) TrimEvent(Spect } } + // find a potentially more accurate end frame int endFrameOffset = 0; - for (int frame = frameAverages.Length - 1; frame >= 0; frame--) + for (int frame = frameAverages.Length - 1; frame > 0; frame--) { endFrameOffset++; if (frameAverages[frame - 1] >= threshold && frameAverages[frame] < threshold) @@ -76,10 +86,21 @@ public static (int EventStart, int EventEnd, double FramePeriod) TrimEvent(Spect } } - int trueStartFrame = startFrame + startFrameOffset; - int trueEndFrame = endFrame - endFrameOffset; + int revisedStartFrame = startFrame + startFrameOffset; + int revisedEndFrame = endFrame - endFrameOffset; + + // the above algorithm may produce faulty result for some situations. + // This is a sanity check. + int revisedEventLength = revisedEndFrame - revisedStartFrame + 1; + if (revisedEventLength < frameAverages.Length * 0.75) + { + // if revised event length is too short, return to original start and end values + revisedStartFrame = startFrame; + revisedEndFrame = endFrame; + } - // determine the number of times the frame values step from below to above threshold. + // Now obtain the oscillation event's periodicity. + // Determine the number of times the frame values step from below to above threshold. // also the frame index in which the steps happen. int stepCount = 0; var peakOnsets = new List(); @@ -96,7 +117,7 @@ public static (int EventStart, int EventEnd, double FramePeriod) TrimEvent(Spect int framePeriods = peakOnsets[peakOnsets.Count - 1] - peakOnsets[0]; double framePeriod = framePeriods / (double)(stepCount - 1); - return (trueStartFrame, trueEndFrame, framePeriod); + return (revisedStartFrame, revisedEndFrame, framePeriod); } } } \ No newline at end of file