Skip to content

Commit

Permalink
Add more file loading tests
Browse files Browse the repository at this point in the history
  • Loading branch information
adamstark committed Mar 24, 2023
1 parent ee1cdde commit 540b6fc
Show file tree
Hide file tree
Showing 3 changed files with 290 additions and 40 deletions.
28 changes: 26 additions & 2 deletions AudioFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,17 @@ bool AudioFile<T>::decodeWaveFile (std::vector<uint8_t>& fileData)
uint16_t numBytesPerBlock = twoBytesToInt (fileData, f + 20);
bitDepth = (int) twoBytesToInt (fileData, f + 22);

if (bitDepth > sizeof (T) * 8)
{
std::string message = "ERROR: you are trying to read a ";
message += std::to_string (bitDepth);
message += "-bit file using a ";
message += std::to_string (sizeof (T) * 8);
message += "-bit sample type";
reportError (message);
return false;
}

uint16_t numBytesPerSample = static_cast<uint16_t> (bitDepth) / 8;

// check that the audio format is PCM or Float or extensible
Expand Down Expand Up @@ -682,7 +693,7 @@ bool AudioFile<T>::decodeWaveFile (std::vector<uint8_t>& fileData)
int32_t sampleAsInt = fourBytesToInt (fileData, sampleIndex);
T sample;

if (audioFormat == WavAudioFormat::IEEEFloat)
if (audioFormat == WavAudioFormat::IEEEFloat && std::is_floating_point_v<T>)
{
float f;
memcpy (&f, &sampleAsInt, sizeof(int32_t));
Expand Down Expand Up @@ -749,6 +760,17 @@ bool AudioFile<T>::decodeAiffFile (std::vector<uint8_t>& fileData)
bitDepth = (int) twoBytesToInt (fileData, p + 14, Endianness::BigEndian);
sampleRate = getAiffSampleRate (fileData, p + 16);

if (bitDepth > sizeof (T) * 8)
{
std::string message = "ERROR: you are trying to read a ";
message += std::to_string (bitDepth);
message += "-bit file using a ";
message += std::to_string (sizeof (T) * 8);
message += "-bit sample type";
reportError (message);
return false;
}

// check the sample rate was properly decoded
if (sampleRate == 0)
{
Expand Down Expand Up @@ -1555,7 +1577,9 @@ T AudioSampleConverter<T>::signedByteToSample (int8_t sample)
template <class T>
T AudioSampleConverter<T>::clamp (T value, T minValue, T maxValue)
{
return value < minValue ? minValue : (value > maxValue ? maxValue : value);
value = std::min (value, maxValue);
value = std::max (value, minValue);
return value;
}

#if defined (_MSC_VER)
Expand Down
231 changes: 195 additions & 36 deletions tests/AiffLoadingTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
const std::string projectBuildDirectory = PROJECT_BINARY_DIR;

//=============================================================
TEST_SUITE ("AiffLoadingTests")
TEST_SUITE ("AiffLoadingTests - Floating Point Types - 8-bit File")
{
//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_8bit_44100")
Expand All @@ -43,7 +43,32 @@ TEST_SUITE ("AiffLoadingTests")
}
}
}

//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_8bit_48000")
{
AudioFile<double> audioFile;
bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_8bit_48000.aif");

CHECK (loadedOK);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_8bit_48000::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_8bit_48000::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_8bit_48000::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_8bit_48000::numChannels);

for (size_t i = 0; i < aiff_stereo_8bit_48000::testBuffer[0].size(); i++)
{
for (int k = 0; k < audioFile.getNumChannels(); k++)
{
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_8bit_48000::testBuffer[k][i]).epsilon (0.01));
}
}
}
}

//=============================================================
TEST_SUITE ("AiffLoadingTests - Floating Point Types - 16-bit File")
{
//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_16bit_44100")
{
Expand All @@ -64,7 +89,32 @@ TEST_SUITE ("AiffLoadingTests")
}
}
}

//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_16bit_48000")
{
AudioFile<double> audioFile;
bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_16bit_48000.aif");

CHECK (loadedOK);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_16bit_48000::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_16bit_48000::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_16bit_48000::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_16bit_48000::numChannels);

for (size_t i = 0; i < aiff_stereo_16bit_48000::testBuffer[0].size(); i++)
{
for (int k = 0; k < audioFile.getNumChannels(); k++)
{
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_16bit_48000::testBuffer[k][i]).epsilon (0.00001));
}
}
}
}

//=============================================================
TEST_SUITE ("AiffLoadingTests - Floating Point Types - 24-bit File")
{
//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_24bit_44100")
{
Expand All @@ -85,7 +135,32 @@ TEST_SUITE ("AiffLoadingTests")
}
}
}

//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_24bit_48000")
{
AudioFile<double> audioFile;
bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_24bit_48000.aif");

CHECK (loadedOK);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_24bit_48000::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_24bit_48000::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_24bit_48000::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_24bit_48000::numChannels);

for (size_t i = 0; i < aiff_stereo_24bit_48000::testBuffer[0].size(); i++)
{
for (int k = 0; k < audioFile.getNumChannels(); k++)
{
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_24bit_48000::testBuffer[k][i]).epsilon (0.00001));
}
}
}
}

//=============================================================
TEST_SUITE ("AiffLoadingTests - Floating Point Types - 32-bit File")
{
//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_32bit_44100")
{
Expand All @@ -108,86 +183,170 @@ TEST_SUITE ("AiffLoadingTests")
}

//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_8bit_48000")
TEST_CASE ("AiffLoadingTests_Stereo_32bit_48000")
{
AudioFile<double> audioFile;
bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_8bit_48000.aif");
bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_32bit_48000.aif");

CHECK (loadedOK);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_8bit_48000::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_8bit_48000::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_8bit_48000::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_8bit_48000::numChannels);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_32bit_48000::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_32bit_48000::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_32bit_48000::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_32bit_48000::numChannels);

for (size_t i = 0; i < aiff_stereo_8bit_48000::testBuffer[0].size(); i++)
for (size_t i = 0; i < aiff_stereo_32bit_48000::testBuffer[0].size(); i++)
{
for (int k = 0; k < audioFile.getNumChannels(); k++)
{
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_8bit_48000::testBuffer[k][i]).epsilon (0.01));
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_32bit_48000::testBuffer[k][i]).epsilon (0.00001));
}
}
}
}

//=============================================================
TEST_SUITE ("AiffLoadingTests - Integer Types - 8-bit File")
{
//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_16bit_48000")
template <typename T>
void test8Bit44100WithInteger (bool expectFailure = false)
{
AudioFile<double> audioFile;
bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_16bit_48000.aif");
AudioFile<T> audioFile;
bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_8bit_44100.aif");

CHECK (loadedOK);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_16bit_48000::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_16bit_48000::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_16bit_48000::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_16bit_48000::numChannels);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_8bit_44100::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_8bit_44100::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_8bit_44100::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_8bit_44100::numChannels);

for (size_t i = 0; i < aiff_stereo_16bit_48000::testBuffer[0].size(); i++)
int offset = std::is_signed_v<T> ? 0 : 128;

for (size_t i = 0; i < aiff_stereo_8bit_44100::testBuffer[0].size(); i++)
{
for (int k = 0; k < audioFile.getNumChannels(); k++)
{
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_16bit_48000::testBuffer[k][i]).epsilon (0.00001));
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_8bit_44100::testBuffer[k][i] * 127 + offset).epsilon (0.01));
}
}
}

//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_8bit_44100_integers")
{
test8Bit44100WithInteger<int8_t>();
test8Bit44100WithInteger<uint8_t>();
test8Bit44100WithInteger<int16_t>();
test8Bit44100WithInteger<uint16_t>();
test8Bit44100WithInteger<int32_t>();
test8Bit44100WithInteger<uint32_t>();
test8Bit44100WithInteger<int64_t>();
test8Bit44100WithInteger<uint64_t>();
}
}

//=============================================================
TEST_SUITE ("AiffLoadingTests - Integer Types - 16-bit File")
{
//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_24bit_48000")
template <typename T>
void test16Bit44100WithInteger (bool expectFailure = false)
{
AudioFile<double> audioFile;
bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_24bit_48000.aif");
AudioFile<T> audioFile;

if (expectFailure)
audioFile.shouldLogErrorsToConsole (false);

bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_16bit_44100.aif");

if (expectFailure)
{
CHECK_EQ (loadedOK, false);
return;
}

CHECK (loadedOK);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_24bit_48000::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_24bit_48000::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_24bit_48000::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_24bit_48000::numChannels);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_16bit_44100::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_16bit_44100::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_16bit_44100::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_16bit_44100::numChannels);

for (size_t i = 0; i < aiff_stereo_24bit_48000::testBuffer[0].size(); i++)
int offset = std::is_signed_v<T> ? 0 : 32768;

for (size_t i = 0; i < aiff_stereo_16bit_44100::testBuffer[0].size(); i++)
{
for (int k = 0; k < audioFile.getNumChannels(); k++)
{
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_24bit_48000::testBuffer[k][i]).epsilon (0.00001));
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_16bit_44100::testBuffer[k][i] * 32767 + offset).epsilon (0.0001));
}
}
}

//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_16bit_44100_integers")
{
test16Bit44100WithInteger<uint16_t>();
test16Bit44100WithInteger<int16_t>();
test16Bit44100WithInteger<uint32_t>();
test16Bit44100WithInteger<int32_t>();
test16Bit44100WithInteger<uint64_t>();
test16Bit44100WithInteger<int64_t>();

// check these fail...
test16Bit44100WithInteger<uint8_t> (true);
test16Bit44100WithInteger<int8_t> (true);
}
}

//=============================================================
TEST_SUITE ("AiffLoadingTests - Integer Types - 24-bit File")
{
//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_32bit_48000")
template <typename T>
void test24Bit44100WithInteger (bool expectFailure = false)
{
AudioFile<double> audioFile;
bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_32bit_48000.aif");
AudioFile<T> audioFile;

if (expectFailure)
audioFile.shouldLogErrorsToConsole (false);

bool loadedOK = audioFile.load (projectBuildDirectory + "/test-audio/aiff_stereo_24bit_44100.aif");

if (expectFailure)
{
REQUIRE_EQ (loadedOK, false);
return;
}

CHECK (loadedOK);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_32bit_48000::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_32bit_48000::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_32bit_48000::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_32bit_48000::numChannels);
CHECK_EQ (audioFile.getNumSamplesPerChannel(), aiff_stereo_24bit_44100::numSamplesPerChannel);
CHECK_EQ (audioFile.getBitDepth(), aiff_stereo_24bit_44100::bitDepth);
CHECK_EQ (audioFile.getSampleRate(), aiff_stereo_24bit_44100::sampleRate);
CHECK_EQ (audioFile.getNumChannels(), aiff_stereo_24bit_44100::numChannels);

for (size_t i = 0; i < aiff_stereo_32bit_48000::testBuffer[0].size(); i++)
int offset = std::is_signed_v<T> ? 0 : 8388608;

for (size_t i = 0; i < aiff_stereo_24bit_44100::testBuffer[0].size(); i++)
{
for (int k = 0; k < audioFile.getNumChannels(); k++)
{
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_32bit_48000::testBuffer[k][i]).epsilon (0.00001));
CHECK (audioFile.samples[k][i] == doctest::Approx (aiff_stereo_24bit_44100::testBuffer[k][i] * 8388607 + offset).epsilon (0.00001));
}
}
}

//=============================================================
TEST_CASE ("AiffLoadingTests_Stereo_24bit_44100_integers")
{
test24Bit44100WithInteger<int32_t>();
test24Bit44100WithInteger<uint32_t>();
test24Bit44100WithInteger<int64_t>();
test24Bit44100WithInteger<uint64_t>();

// check these fail...
test24Bit44100WithInteger<int8_t> (true);
test24Bit44100WithInteger<uint8_t> (true);
test24Bit44100WithInteger<int16_t> (true);
test24Bit44100WithInteger<uint16_t> (true);
}
}
Loading

0 comments on commit 540b6fc

Please sign in to comment.