Skip to content

Commit

Permalink
Automate calculation of Octave scale bounds and its gridlines.
Browse files Browse the repository at this point in the history
Issue #332 Also need to add a new test for calculating grid locations and fix other tests.
  • Loading branch information
towsey committed Aug 12, 2020
1 parent f3eb3ed commit 0a643f1
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 259 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,17 @@ public static AudioToSonogramResult GenerateSpectrogramImages(
NoiseReductionParameter = bgNoiseThreshold,
};

// Here are some of the possible octave frequency scales.
//var freqScale = new FrequencyScale(FreqScaleType.LinearOctaveStandard);
//var freqScale = new FrequencyScale(FreqScaleType.OctaveDataReduction);
//var freqScale = new FrequencyScale(FreqScaleType.Linear62OctaveTones31Nyquist11025);
//var freqScale = new FrequencyScale(FreqScaleType.Linear125OctaveTones32Nyquist11025);
//var type = FreqScaleType.OctaveCustom;
var type = FreqScaleType.OctaveStandard;
int nyquist = sampleRate / 2;
int linearBound = 1000;
int octaveToneCount = 31; // This value is ignored for OctaveStandard type.
int hertzGridInterval = 1000;
var scale = new FrequencyScale(type, nyquist, frameSize, linearBound, octaveToneCount, hertzGridInterval);

images.Add(
OctaveScaleSpectrogram,
GetOctaveScaleSpectrogram(octaveConfig, FreqScaleType.Linear62OctaveTones31Nyquist11025, recordingSegment, sourceRecordingName));
GetOctaveScaleSpectrogram(octaveConfig, scale, recordingSegment, sourceRecordingName));
}

// IMAGE 9) AmplitudeSpectrogram_LocalContrastNormalization
Expand Down Expand Up @@ -391,7 +393,7 @@ public static Image<Rgb24> GetMelScaleSpectrogram(
var titleBar = BaseSonogram.DrawTitleBarOfGrayScaleSpectrogram(
"MEL-FREQUENCY SPECTROGRAM " + sourceRecordingName,
image.Width,
ImageTags[CepstralSpectrogram]);
ImageTags[MelScaleSpectrogram]);
var startTime = TimeSpan.Zero;
var xAxisTicInterval = TimeSpan.FromSeconds(1);
TimeSpan xAxisPixelDuration = TimeSpan.FromSeconds(sonoConfig.WindowStep / (double)sonoConfig.SampleRate);
Expand Down Expand Up @@ -424,15 +426,10 @@ public static Image<Rgb24> GetCepstralSpectrogram(

public static Image<Rgb24> GetOctaveScaleSpectrogram(
SonogramConfig sgConfig,
FreqScaleType fst,
FrequencyScale freqScale,
AudioRecording recording,
string sourceRecordingName)
{
var freqScale = new FrequencyScale(fst)
{
WindowStep = 512,
};

// ensure that the freq scale and the config are consistent.
sgConfig.WindowSize = freqScale.WindowSize;
freqScale.WindowStep = sgConfig.WindowStep;
Expand All @@ -447,7 +444,7 @@ public static Image<Rgb24> GetOctaveScaleSpectrogram(
var titleBar = BaseSonogram.DrawTitleBarOfGrayScaleSpectrogram(
"OCTAVE-SCALE SPECTROGRAM " + sourceRecordingName,
image.Width,
ImageTags[CepstralSpectrogram]);
ImageTags[OctaveScaleSpectrogram]);
var startTime = TimeSpan.Zero;
var xAxisTicInterval = TimeSpan.FromSeconds(1);
TimeSpan xAxisPixelDuration = TimeSpan.FromSeconds(sgConfig.WindowStep / (double)sgConfig.SampleRate);
Expand Down
9 changes: 8 additions & 1 deletion src/AudioAnalysisTools/DSP/DSP_Filters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,14 @@ public static void TestMethod_GenerateSignal2()
int sampleRate = 64000;
double duration = 30; // signal duration in seconds
int[] harmonics = { 500, 1000, 2000, 4000, 8000 };
var freqScale = new FrequencyScale(FreqScaleType.Linear125OctaveTones28Nyquist32000);

//var freqScale = new FrequencyScale(FreqScaleType.Linear125OctaveTones28Nyquist32000);
int nyquist = sampleRate / 2;
int frameSize = 16384;
int linearBound = 125;
int octaveToneCount = 28;
int gridInterval = 1000;
var freqScale = new FrequencyScale(FreqScaleType.OctaveCustom, nyquist, frameSize, linearBound, octaveToneCount, gridInterval);
string path = @"C:\SensorNetworks\Output\Sonograms\UnitTestSonograms\SineSignal2.png";
var recording = GenerateTestRecording(sampleRate, duration, harmonics, WaveType.Cosine);

Expand Down
75 changes: 66 additions & 9 deletions src/AudioAnalysisTools/DSP/FrequencyScale.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,9 @@ public enum FreqScaleType
{
Linear = 0,
Mel = 1,
LinearOctaveStandard = 2,
Linear62OctaveTones31Nyquist11025 = 3,
Linear125OctaveTones32Nyquist11025 = 4,
Linear125OctaveTones28Nyquist32000 = 5,
Octaves24Nyquist32000 = 6,
OctaveDataReduction = 7,
OctaveCustom = 2,
OctaveStandard = 3,
OctaveDataReduction = 3,
}

public class FrequencyScale
Expand Down Expand Up @@ -59,7 +56,6 @@ public FrequencyScale(int nyquist, int frameSize, int hertzGridInterval)
/// </summary>
public FrequencyScale(FreqScaleType type, int nyquist, int frameSize, int finalBinCount, int hertzGridInterval)
{
this.ScaleType = type;
this.Nyquist = nyquist;
this.WindowSize = frameSize;
this.FinalBinCount = finalBinCount;
Expand All @@ -70,6 +66,10 @@ public FrequencyScale(FreqScaleType type, int nyquist, int frameSize, int finalB
this.GridLineLocations = SpectrogramMelScale.GetMelGridLineLocations(this.HertzGridInterval, nyquist, this.FinalBinCount);
this.LinearBound = 1000;
}
else if (type == FreqScaleType.OctaveStandard || type == FreqScaleType.OctaveCustom)
{
throw new Exception("Wrong Constructor. Use the Octave scale constructor.");
}
else
{
// linear is the default
Expand All @@ -79,6 +79,51 @@ public FrequencyScale(FreqScaleType type, int nyquist, int frameSize, int finalB
}
}

/// <summary>
/// Initializes a new instance of the <see cref="FrequencyScale"/> class.
/// CONSTRUCTION OF OCTAVE Frequency Scales
/// IMPORTANT NOTE: If you are converting Herz scale from LINEAR to OCTAVE, this conversion MUST be done BEFORE noise reduction
/// WARNING!: Changing the constants for the octave scales will have undefined effects.
/// The options below have been debugged to give what is required.
/// However other values have not been debugged - so user should check the output to ensure it is what is required.
/// NOTE: octaveToneCount = the number of fractional Hz steps within one octave. A piano octave contains 12 steps per octave.
/// NOTE: Not all combinations of parameter values are effective. nor have they all been tested.
/// The following have been tested:
/// nyquist=11025, linearBound=125 t0 1000, octaveToneCount=31, 32.
/// nyquist=11025, linearBound=125, octaveToneCount=31.
/// nyquist=32000, linearBound=125, octaveToneCount=28.
/// </summary>
/// <param name="type">Scale type must be an OCTAVE type.</param>
/// <param name="nyquist">sr / 2.</param>
/// <param name="frameSize">Assumes that frame size is power of 2.</param>
/// <param name="linearBound">The bound (Hz value) that divides lower linear and upper octave parts of the frequency scale.</param>
/// <param name="octaveToneCount">Number of fractional Hz steps within one octave. This is ignored in case of custom scale.</param>
/// <param name="hertzGridInterval">Only used where appropriate to draw frequency gridlines.</param>
public FrequencyScale(FreqScaleType type, int nyquist, int frameSize, int linearBound, int octaveToneCount, int hertzGridInterval)
{
this.ScaleType = type;
this.Nyquist = nyquist;
this.WindowSize = frameSize;
this.LinearBound = linearBound;

if (type == FreqScaleType.OctaveStandard)
{
// this scale automatically sets the octave tone count.
OctaveFreqScale.GetStandardOctaveScale(this);
}
else if (type == FreqScaleType.OctaveCustom)
{
this.ToneCount = octaveToneCount;
this.BinBounds = OctaveFreqScale.LinearToSplitLinearOctaveScale(nyquist, frameSize, linearBound, nyquist, octaveToneCount);
this.FinalBinCount = this.BinBounds.GetLength(0);
this.GridLineLocations = OctaveFreqScale.GetGridLineLocations(nyquist, linearBound, this.BinBounds);
}
else
{
throw new Exception("Unknown Octave scale.");
}
}

/// <summary>
/// Initializes a new instance of the <see cref="FrequencyScale"/> class.
/// CONSTRUCTOR.
Expand All @@ -104,10 +149,22 @@ public FrequencyScale(FreqScaleType fst)
// MEL SCALE spectrograms are available by direct call to SpectrogramGenerator.Core.GetMelScaleSpectrogram()
SpectrogramMelScale.GetStandardMelScale(this);
}
else if (fst == FreqScaleType.OctaveDataReduction)
{
// This spectral conversion is for data reduction purposes.
// It is a split linear-octave frequency scale.
OctaveFreqScale.GetDataReductionScale(this);

//The data reduction Octave Scale does not require grid lines.
this.GridLineLocations = new int[6, 2];
}
else if (fst == FreqScaleType.OctaveStandard || fst == FreqScaleType.OctaveCustom)
{
throw new Exception("Not enough info. Use an Octave scale constructor.");
}
else
{
// assume octave scale is only other option
OctaveFreqScale.GetOctaveScale(this);
throw new Exception("Unknown frequency scale type.");
}
}

Expand Down
Loading

0 comments on commit 0a643f1

Please sign in to comment.