diff options
author | Jamie Bullock <jamie@jamiebullock.com> | 2014-11-11 17:30:17 +0000 |
---|---|---|
committer | Jamie Bullock <jamie@jamiebullock.com> | 2014-11-11 17:30:17 +0000 |
commit | b3b6e6fd6b39e7f2bbbd8e2209302590d6d155eb (patch) | |
tree | 1e6aa9e0feb6ce30749bc9fa52dacb424378ba75 | |
parent | 25a004e7c9d70ddf16e044536871cba2f818936d (diff) | |
download | LibXtract-b3b6e6fd6b39e7f2bbbd8e2209302590d6d155eb.tar.gz LibXtract-b3b6e6fd6b39e7f2bbbd8e2209302590d6d155eb.tar.bz2 LibXtract-b3b6e6fd6b39e7f2bbbd8e2209302590d6d155eb.zip |
Add sawtooth tests
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | tests/.xttest_scalar.cpp.swp | bin | 0 -> 57344 bytes | |||
-rw-r--r-- | tests/xttest_scalar.cpp | 554 | ||||
-rw-r--r-- | tests/xttest_util.cpp | 12 | ||||
-rw-r--r-- | tests/xttest_util.hpp | 3 |
6 files changed, 569 insertions, 3 deletions
@@ -36,7 +36,6 @@ The generated HTML documentation can then be viewed in a web browser by opening **Pre-generated documentation can be found on the [LibXtract website](http://jamiebullock.github.io/LibXtract/documentation)** - ## LicenseĀ Copyright (C) 2012 Jamie Bullock @@ -1 +1 @@ -0.7.2 +0.8.0 diff --git a/tests/.xttest_scalar.cpp.swp b/tests/.xttest_scalar.cpp.swp Binary files differnew file mode 100644 index 0000000..f730587 --- /dev/null +++ b/tests/.xttest_scalar.cpp.swp diff --git a/tests/xttest_scalar.cpp b/tests/xttest_scalar.cpp index 29549b4..755f685 100644 --- a/tests/xttest_scalar.cpp +++ b/tests/xttest_scalar.cpp @@ -532,3 +532,557 @@ SCENARIO( "F0 is correctly detected for a sine wave", "[xtract_f0]" ) } } } + +SCENARIO( "F0 is correctly detected for a sawtooth wave", "[xtract_f0]" ) +{ + uint16_t expected = 0; + uint16_t actual = 0; + + GIVEN( "a 512 sample block with a sample rate of 44100" ) + { + uint32_t blocksize = 512; + double samplerate = 44100; + double result = -1.0; + double amplitude = 1.0; + double table[blocksize]; + + WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 1 cycles in the block + { + double frequency = 86.1328125; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + int rv = xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "frequency detection fails correctly (XTRACT_NO_RESULT is returned, result set to 0.0)" ) + { + REQUIRE(rv == XTRACT_NO_RESULT); + REQUIRE(result == 0.0); + } + } + + WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 2 cycles in the block + { + double frequency = 172.265625; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + int rv = xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + + WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 4 cycles in the block + { + double frequency = 344.53125; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + + + WHEN( "the amplitude is 0.01" ) // Only test a different amplitude for one case + { + double amplitude = 0.01; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + } + } + + GIVEN( "a 1024 sample block with a sample rate of 44100" ) + { + uint32_t blocksize = 1024; + double samplerate = 44100; + double result = -1.0; + double amplitude = 1.0; + double table[blocksize]; + + WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 2 cycles in the block + { + double frequency = 86.1328125; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + int rv = xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "the frequency is 140 Hz" ) // period of 315 samples: 3.25 cycles in the block + { + double frequency = 140; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest MIDI cent" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE(actual == expected); + } + } + + WHEN( "the frequency is 155 Hz" ) // period of 284.52 samples: 3.6 cycles in the block + { + double frequency = 155; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is quantized to the nearest whole number of samples" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(155.28169014); // period of 284 samples + CAPTURE( result ); + CAPTURE( expected ); + REQUIRE(actual == expected); + } + } + + + WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 4 cycles in the block + { + double frequency = 172.265625; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 8 cycles in the block + { + double frequency = 344.53125; + double noise[blocksize]; + expected = xttest_ftom(frequency); + CAPTURE( expected ); + + WHEN( "the amplitude is 1.0" ) + { + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "the amplitude is 0.01" ) // Only test a different amplitude for one case + { + amplitude = 0.01; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "white noise is added at 10%" ) // Only test noise for one case + { + amplitude = 0.1; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); + xttest_gen_noise(noise, blocksize, amplitude); + xttest_add(table, noise, blocksize); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "white noise is added at 20%" ) + { + amplitude = 0.2; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); + xttest_gen_noise(noise, blocksize, amplitude); + xttest_add(table, noise, blocksize); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "white noise is added at 25%" ) + { + amplitude = 0.25; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); + xttest_gen_noise(noise, blocksize, amplitude); + xttest_add(table, noise, blocksize); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "white noise is added at 30%" ) + { + amplitude = 0.25; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); + xttest_gen_noise(noise, blocksize, amplitude); + xttest_add(table, noise, blocksize); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "white noise is added at 35%" ) + { + amplitude = 0.35; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); + xttest_gen_noise(noise, blocksize, amplitude); + xttest_add(table, noise, blocksize); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + } + } + + GIVEN( "a 1024 sample block with a sample rate of 11025" ) + { + uint32_t blocksize = 1024; + double samplerate = 11025; + double result = -1.0; + double table[blocksize]; + + WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 2 cycles in the block + { + double frequency = 86.1328125; + double amplitude = 1.0; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + int rv = xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 4 cycles in the block + { + double frequency = 172.265625; + double amplitude = 1.0; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 8 cycles in the block + { + double frequency = 344.53125; + expected = xttest_ftom(frequency); + CAPTURE( expected ); + + WHEN( "the amplitude is 1.0" ) + { + double amplitude = 1.0; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "the amplitude is 0.01" ) // Only test a different amplitude for one case + { + double amplitude = 0.01; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "white noise is added at 20%" ) + { + double amplitude = 0.2; + double noise[blocksize]; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); + xttest_gen_noise(noise, blocksize, amplitude); + xttest_add(table, noise, blocksize); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "white noise is added at 40%" ) + { + double amplitude = 0.4; + double noise[blocksize]; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); + xttest_gen_noise(noise, blocksize, amplitude); + xttest_add(table, noise, blocksize); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is inaccurate by more than one semitone" ) + { + actual = xttest_ftom(result); + uint16_t difference = abs(expected - actual); + CAPTURE( actual ); + REQUIRE( difference > 100 ); + } + } + } + } + + GIVEN( "a 2048 sample block with a sample rate of 44100" ) + { + uint32_t blocksize = 2048; + double samplerate = 44100; + double result = -1.0; + double table[blocksize]; + + WHEN( "the frequency is 43.06640625 Hz" ) // period of exactly 256 samples: 2 cycles in the block + { + double frequency = 43.06640625; + double amplitude = 1.0; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + int rv = xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest quarter-tone" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + uint16_t min = expected - 50; + uint16_t max = expected + 50; + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE( actual > min ); + REQUIRE( actual < max ); + } + } + + WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 4 cycles in the block + { + double frequency = 86.1328125; + double amplitude = 1.0; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + int rv = xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest MIDI cent" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE(actual == expected); + } + } + + WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 8 cycles in the block + { + double frequency = 172.265625; + double amplitude = 1.0; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest MIDI cent" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE(actual == expected); + } + } + + WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 16 cycles in the block + { + double frequency = 344.53125; + + WHEN( "the amplitude is 1.0" ) + { + double amplitude = 1.0; + + xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); + xtract_f0(table, blocksize, &samplerate, &result); + + THEN( "the detected F0 is accurate to the nearest MIDI cent" ) + { + actual = xttest_ftom(result); + expected = xttest_ftom(frequency); + CAPTURE( actual ); + CAPTURE( expected ); + REQUIRE(actual == expected); + } + } + } + } +} + diff --git a/tests/xttest_util.cpp b/tests/xttest_util.cpp index 47fbf8a..c10ff53 100644 --- a/tests/xttest_util.cpp +++ b/tests/xttest_util.cpp @@ -22,6 +22,17 @@ void xttest_gen_sine(double *table, uint32_t tablesize, double samplerate, doubl } } +void xttest_gen_sawtooth(double *table, uint32_t tablesize, double samplerate, double frequency, double amplitude) +{ + int samples_per_period = samplerate / frequency; + + for (uint32_t i = 0; i < tablesize; ++i) + { + int phase = i % samples_per_period; + table[i] = ((phase / (double)samples_per_period) * 2.0 - 1.0) * amplitude; + } +} + void xttest_gen_noise(double *table, uint32_t tablesize, double amplitude) { for (uint32_t i = 0; i < tablesize; ++i) @@ -30,7 +41,6 @@ void xttest_gen_noise(double *table, uint32_t tablesize, double amplitude) } } - uint16_t xttest_ftom(double frequency) { return (int)roundf(6900.0 + 1200.0 * log2(frequency / 440.0)); diff --git a/tests/xttest_util.hpp b/tests/xttest_util.hpp index 381f2cf..dbf075c 100644 --- a/tests/xttest_util.hpp +++ b/tests/xttest_util.hpp @@ -5,6 +5,9 @@ // Fill table with sine wave at given frequency and amplitude void xttest_gen_sine(double *table, uint32_t tablesize, double samplerate, double frequency, double amplitude); +// Fill table with sawtooth wave at given frequency and amplitude +void xttest_gen_sawtooth(double *table, uint32_t tablesize, double samplerate, double frequency, double amplitude); + // Fill table with noise at given frequency and amplitude // N.B. The implementation actually provides "fake" noise from a table for reproducible testing void xttest_gen_noise(double *table, uint32_t tablesize, double amplitude); |