Skip to content

Commit

Permalink
More changes to do with pre-emphasis of an audio signal
Browse files Browse the repository at this point in the history
Issue #492
  • Loading branch information
towsey committed May 27, 2021
1 parent 8561315 commit fcb0a12
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 8 deletions.
4 changes: 2 additions & 2 deletions src/AudioAnalysisTools/DSP/DSP_Filters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ public static double[] GetSignalOfAddedSines(int sampleRate, double duration, in
/// <summary>
/// The source signal for voiced speech, that is, the vibration generated by the glottis or vocal chords,
/// has a spectral content with more power in low freq than in high. The spectrum has roll off of -6dB/octave.
/// Many speech analysis methods work better when the souce signal is spectrally flattened.
/// This is achieved by a high pass filter.
/// Many speech analysis methods work better when the source signal is spectrally flattened.
/// The pre-emphasis filter is just a 1-order FIR filter, with gentle roll-off.
/// </summary>
public static double[] PreEmphasis(double[] signal, double coeff)
{
Expand Down
94 changes: 90 additions & 4 deletions tests/Acoustics.Test/AudioAnalysisTools/DSP/EnvelopeAndFftTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,23 @@ public void TestEnvelopeAndFft1()
var recording = new AudioRecording(PathHelper.ResolveAsset("Recordings", "BAC2_20071008-085040.wav"));
int windowSize = 512;

// window overlap is used only for sonograms. It is not used when calculating acoustic indices.
// set default value for pre-emphasis.
// set true ony when dealing with human speech.
bool doPreemphasis = false;

// window overlap is used only for spectrograms. It is not used when calculating acoustic indices.
double windowOverlap = 0.0;
var windowFunction = WindowFunctions.HAMMING.ToString();

var fftdata = DSP_Frames.ExtractEnvelopeAndFfts(
recording,
doPreemphasis,
windowSize,
windowOverlap,
windowFunction);

// Now recover the data
// The following data is required when constructing sonograms
// The following data is required when constructing spectrograms
var duration = recording.WavReader.Time;
var sr = recording.SampleRate;
var frameCount = fftdata.FrameCount;
Expand Down Expand Up @@ -109,6 +114,8 @@ public void TestEnvelopeAndFft1()
var avgDelta = expectedColSums.Zip(columnSums, ValueTuple.Create).Select(x => Math.Abs(x.Item1 - x.Item2)).Average();
Assert.AreEqual(expectedColSums[0], columnSums[0], Delta, $"\nE: {expectedColSums[0]:R}\nA: {columnSums[0]:R}\nD: {expectedColSums[0] - columnSums[0]:R}\nT: {totalDelta:R}\nA: {avgDelta}\nn: {expectedColSums.Length}");
CollectionAssert.That.AreEqual(expectedColSums, columnSums, Delta);

//FileTools.WriteArray2File_Formatted(expectedColSums, "C:\\temp\\array.txt", "0.00");
}

/// <summary>
Expand All @@ -122,20 +129,25 @@ public void TestEnvelopeAndFft2()
var recording = new AudioRecording(PathHelper.ResolveAsset("Recordings", "BAC2_20071008-085040.wav"));
int windowSize = 512;

// window overlap is used only for sonograms. It is not used when calculating acoustic indices.
// set default value for pre-emphasis.
// set true ony when dealing with human speech.
bool doPreemphasis = false;

// window overlap is used only for spectrograms. It is not used when calculating acoustic indices.
double windowOverlap = 0.0;
var windowFunction = WindowFunctions.HAMMING.ToString();

var fftdata = DSP_Frames.ExtractEnvelopeAndFfts(
recording,
doPreemphasis,
windowSize,
windowOverlap,
windowFunction);

// Now recover the data

/*
// The following data is required when constructing sonograms
// The following data is required when constructing spectrograms
var duration = recording.WavReader.Time;
var sr = recording.SampleRate;
var frameCount = fftdata.FrameCount;
Expand Down Expand Up @@ -208,5 +220,79 @@ public void TestEnvelopeAndFft2()
Assert.AreEqual(11025, nyquistFreq);
Assert.AreEqual(43.0664, freqBinWidth, 0.00001);
}

/// <summary>
/// Test the output from EnvelopeAndFft.
/// This is the same as TestEnvelopeAndFft1() EXCEPT that Pre-empahsis is set true.
/// Pre-empahsis is set true only when dealing speech. Never when calculating acoustic indices.
/// Only test those variables that are used to construct sonograms.
/// </summary>
[TestMethod]
public void TestEnvelopeAndFft3()
{
var recording = new AudioRecording(PathHelper.ResolveAsset("Recordings", "BAC2_20071008-085040.wav"));
int windowSize = 512;
bool doPreemphasis = true;
double windowOverlap = 0.0;
var windowFunction = WindowFunctions.HAMMING.ToString();

var fftdata = DSP_Frames.ExtractEnvelopeAndFfts(
recording,
doPreemphasis,
windowSize,
windowOverlap,
windowFunction);

// Now recover the data
// The following data is required when constructing sonograms
var duration = recording.WavReader.Time;
var sr = recording.SampleRate;
var frameCount = fftdata.FrameCount;
var fractionOfHighEnergyFrames = fftdata.FractionOfHighEnergyFrames;
var epislon = fftdata.Epsilon;
var windowPower = fftdata.WindowPower;
var amplSpectrogram = fftdata.AmplitudeSpectrogram;

// DO THE TESTS
int expectedSR = 22050;
Assert.AreEqual(expectedSR, sr);
Assert.AreEqual(60.244535147392290249433106575964M, recording.WavReader.ExactDurationSeconds);
Assert.AreEqual(2594, frameCount);
int expectedBitsPerSample = 16;
double expectedEpsilon = Math.Pow(0.5, expectedBitsPerSample - 1);
Assert.AreEqual(expectedEpsilon, epislon);
double expectedWindowPower = 203.0778;
Assert.AreEqual(expectedWindowPower, windowPower, 0.0001);
Assert.AreEqual(0.0, fractionOfHighEnergyFrames, 0.0000001);

// Test sonogram data matrix by comparing the vector of column sums.
double[] columnSums = MatrixTools.SumColumns(amplSpectrogram);

var sumFile = PathHelper.ResolveAsset("EnvelopeAndFft", "BAC2_20071008-085040_DataColumnSums.bin");

// uncomment this to update the binary data. Should be rarely needed
//Binary.Serialize(sumFile, columnSums);

var expectedColSums = Binary.Deserialize<double[]>(sumFile);
var totalDelta = expectedColSums.Zip(columnSums, ValueTuple.Create).Select(x => Math.Abs(x.Item1 - x.Item2)).Sum();
var avgDelta = expectedColSums.Zip(columnSums, ValueTuple.Create).Select(x => Math.Abs(x.Item1 - x.Item2)).Average();
Assert.AreEqual(expectedColSums[0], columnSums[0], Delta, $"\nE: {expectedColSums[0]:R}\nA: {columnSums[0]:R}\nD: {expectedColSums[0] - columnSums[0]:R}\nT: {totalDelta:R}\nA: {avgDelta}\nn: {expectedColSums.Length}");
CollectionAssert.That.AreEqual(expectedColSums, columnSums, Delta);

//FileTools.WriteArray2File_Formatted(expectedColSums, "C:\\temp\\array.txt", "0.00");

// The effect of pre-emphasis on the first 10 signal samples.
//ID -preE +preE
// 0 105.43 10.23
// 1 160.10 10.25
// 2 220.47 12.96
// 3 265.59 17.49
// 4 319.03 24.20
// 5 410.82 35.50
// 6 432.17 40.17
// 7 353.41 34.89
// 8 221.72 24.35
// 9 162.78 21.10
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public void TestStandardNoiseRemoval()

var fftdata = DSP_Frames.ExtractEnvelopeAndFfts(
recording,
false,
windowSize,
windowOverlap,
windowFunction);
Expand Down
4 changes: 3 additions & 1 deletion tests/Acoustics.Test/TestHelpers/TestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,9 @@ public static IAudioUtility GetAudioUtilityWavunpack()

public static void AssertFrequencyInSignal(WavReader wavReader, double[] signal, int[] frequencies, int variance = 1)
{
var fft = DSP_Frames.ExtractEnvelopeAndAmplSpectrogram(signal, wavReader.SampleRate, wavReader.Epsilon, 512, 0.0);
// set default value for preemphasis
bool doPreemphasis = false;
var fft = DSP_Frames.ExtractEnvelopeAndAmplSpectrogram(signal, wavReader.SampleRate, wavReader.Epsilon, doPreemphasis, 512, 0.0);

var histogram = SpectrogramTools.CalculateAvgSpectrumFromEnergySpectrogram(fft.AmplitudeSpectrogram);

Expand Down
Git LFS file not shown

0 comments on commit fcb0a12

Please sign in to comment.