Skip to content

Commit

Permalink
Fill in the gaps in the harmonic score array.
Browse files Browse the repository at this point in the history
Issue #471 When searching for harmonic events, sometimes small gaps appear in the harmonic score array which means the events are too short and therefore rejected. This hack fills in gaps of one or two frames. This problem arises because the maximum DCT coefficient is sometimes of a longer wavelength (lower array index) than the the expected wavelength.
  • Loading branch information
towsey committed Jun 11, 2021
1 parent 15b27c1 commit d25768b
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 15 deletions.
49 changes: 35 additions & 14 deletions src/AudioAnalysisTools/Harmonics/HarmonicParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ public class HarmonicParameters : CommonParameters
public double? DctThreshold { get; set; }

/// <summary>
/// Gets or sets the bottom bound of the rectangle. Units are Hertz.
/// Gets or sets the bottom bound of the gap between formants. Units are Hertz.
/// </summary>
public int? MinFormantGap { get; set; }

/// <summary>
/// Gets or sets the the top bound of the rectangle. Units are Hertz.
/// Gets or sets the the top bound of gap between formants. Units are Hertz.
/// </summary>
public int? MaxFormantGap { get; set; }

Expand All @@ -51,7 +51,6 @@ public static (List<EventCommon> SpectralEvents, List<Plot> DecibelPlots) GetCom
spectrogram,
hp.MinHertz.Value,
hp.MaxHertz.Value,
spectrogram.NyquistFrequency,
decibelThreshold.Value,
hp.DctThreshold.Value,
hp.MinDuration.Value,
Expand All @@ -71,7 +70,6 @@ public static (List<EventCommon> SpectralEvents, double[] AmplitudeArray, double
SpectrogramStandard spectrogram,
int minHz,
int maxHz,
int nyquist,
double decibelThreshold,
double dctThreshold,
double minDuration,
Expand All @@ -80,15 +78,18 @@ public static (List<EventCommon> SpectralEvents, double[] AmplitudeArray, double
int maxFormantGap,
TimeSpan segmentStartOffset)
{
int nyquist = spectrogram.NyquistFrequency;
var sonogramData = spectrogram.Data;
int frameCount = sonogramData.GetLength(0);
int binCount = sonogramData.GetLength(1);

// get the min and max bin of the freq-band of interest.
double freqBinWidth = nyquist / (double)binCount;
int minBin = (int)Math.Round(minHz / freqBinWidth);
int maxBin = (int)Math.Round(maxHz / freqBinWidth);
int bandBinCount = maxBin - minBin + 1;

// extract the sub-band
// extract the sub-band of interest
double[,] subMatrix = MatrixTools.Submatrix(spectrogram.Data, 0, minBin, frameCount - 1, maxBin);

//ii: DETECT HARMONICS
Expand All @@ -104,27 +105,46 @@ public static (List<EventCommon> SpectralEvents, double[] AmplitudeArray, double
{
if (harmonicIntensityScores[r] < dctThreshold)
{
//ignore frames where DCT coefficient (proxy for formant intensity) is below threshold
continue;
}

//ignore locations with incorrect formant gap
//ignore frames with incorrect formant gap
// first get id of the maximum coefficient.
int maxId = maxIndexArray[r];
int bandBinCount = maxBin - minBin + 1;
double freqBinGap = 2 * bandBinCount / (double)maxId;
double formantGap = freqBinGap * freqBinWidth;

// remove values where formantGap lies outside the expected range.
if (formantGap < minFormantGap || formantGap > maxFormantGap)
{
harmonicIntensityScores[r] = 0.0;
}
}

// smooth the harmonicIntensityScores array to allow for brief gaps.
harmonicIntensityScores = DataTools.filterMovingAverageOdd(harmonicIntensityScores, 3);
// fill in brief gaps of one or two frames.
var harmonicIntensityScores2 = new double[harmonicIntensityScores.Length];
for (int r = 1; r < frameCount - 2; r++)
{
harmonicIntensityScores2[r] = harmonicIntensityScores[r];
if (harmonicIntensityScores[r - 1] > dctThreshold && harmonicIntensityScores[r] < dctThreshold)
{
// we have arrived at a possible gap. Fill the gap.
harmonicIntensityScores2[r] = harmonicIntensityScores[r - 1];
}

//now check if the gap is two frames wide
if (harmonicIntensityScores[r + 1] < dctThreshold && harmonicIntensityScores[r + 2] > dctThreshold)
{
harmonicIntensityScores2[r + 1] = harmonicIntensityScores[r + 2];
r += 1;
}
}

//extract the events based on length and threshhold.
// Note: This method does NOT do prior smoothing of the score array.
var harmonicEvents = AcousticEvent.ConvertScoreArray2Events(
harmonicIntensityScores,
//extract the events based on length and threshhold.
// Note: This method does NOT do prior smoothing of the score array.
var harmonicEvents = AcousticEvent.ConvertScoreArray2Events(
harmonicIntensityScores2,
minHz,
maxHz,
spectrogram.FramesPerSecond,
Expand All @@ -134,6 +154,7 @@ public static (List<EventCommon> SpectralEvents, double[] AmplitudeArray, double
maxDuration,
segmentStartOffset);

//var spectralEvents = new List<HarmonicEvent>();
var spectralEvents = new List<EventCommon>();

// add in temporary names to the events. These can be altered later.
Expand All @@ -144,7 +165,7 @@ public static (List<EventCommon> SpectralEvents, double[] AmplitudeArray, double
se.Name = "Harmonics";
}

return (spectralEvents, dBArray, harmonicIntensityScores);
return (spectralEvents, dBArray, harmonicIntensityScores2);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,6 @@ public void TestHarmonicsAlgorithm()
spectrogram,
minHertz,
maxHertz,
spectrogram.NyquistFrequency,
decibelThreshold,
dctThreshold,
minDuration,
Expand Down

0 comments on commit d25768b

Please sign in to comment.