aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--VERSION2
-rw-r--r--tests/.xttest_scalar.cpp.swpbin0 -> 57344 bytes
-rw-r--r--tests/xttest_scalar.cpp554
-rw-r--r--tests/xttest_util.cpp12
-rw-r--r--tests/xttest_util.hpp3
6 files changed, 569 insertions, 3 deletions
diff --git a/README.md b/README.md
index bdddb1f..1c27dc0 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/VERSION b/VERSION
index 7486fdb..a3df0a6 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.7.2
+0.8.0
diff --git a/tests/.xttest_scalar.cpp.swp b/tests/.xttest_scalar.cpp.swp
new file mode 100644
index 0000000..f730587
--- /dev/null
+++ b/tests/.xttest_scalar.cpp.swp
Binary files differ
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);