Skip to content

Commit

Permalink
Update OscillationEvent.cs
Browse files Browse the repository at this point in the history
Issue #500
1: Add the OscillationRate readonly property
2: Refactor the algorithm by which the oscillation rate/periodicity of an OscillationEvent is calculated. It was not working for some events. Also add in a sanity check incase the calculation produces badly erroneous result.
  • Loading branch information
towsey committed Jun 28, 2021
1 parent 943ac26 commit c720320
Showing 1 changed file with 30 additions and 9 deletions.
39 changes: 30 additions & 9 deletions src/AudioAnalysisTools/Events/Types/OscillationEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,6 +27,11 @@ public OscillationEvent()
/// </summary>
public double Periodicity { get; set; }

/// <summary>
/// Gets the oascillation rate. This is calculated from the Periodicity. Cannot be set directly.
/// </summary>
public double OscillationRate => 1 / this.Periodicity;

/// <summary>
/// Draws a border around this oscillation event.
/// </summary>
Expand All @@ -44,18 +50,21 @@ public override void Draw(IImageProcessingContext graphics, EventRenderingOption
/// <summary>
/// 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.
/// </summary>
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<double>(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++)
{
Expand All @@ -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)
Expand All @@ -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<int>();
Expand All @@ -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);
}
}
}

0 comments on commit c720320

Please sign in to comment.