jamie@264: jamie@264: #include "xttest_util.hpp" jamie@264: jamie@264: #include "xtract/xtract_scalar.h" jamie@267: #include "xtract/libxtract.h" jamie@264: jamie@264: #include "catch.hpp" jamie@264: jamie@264: jamie@267: SCENARIO( "F0 is correctly detected for a sine wave", "[xtract_f0]" ) jamie@264: { jamie@267: uint16_t expected = 0; jamie@267: uint16_t actual = 0; jamie@268: jamie@267: GIVEN( "a 512 sample block with a sample rate of 44100" ) jamie@267: { jamie@267: uint32_t blocksize = 512; jamie@267: double samplerate = 44100; jamie@267: double result = -1.0; jamie@267: double amplitude = 1.0; jamie@267: double table[blocksize]; jamie@268: jamie@267: WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 1 cycles in the block jamie@267: { jamie@267: double frequency = 86.1328125; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@267: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@267: THEN( "frequency detection fails correctly (XTRACT_NO_RESULT is returned, result set to 0.0)" ) jamie@267: { jamie@267: REQUIRE(rv == XTRACT_NO_RESULT); jamie@267: REQUIRE(result == 0.0); jamie@267: } jamie@267: } jamie@268: jamie@267: WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 2 cycles in the block jamie@267: { jamie@267: double frequency = 172.265625; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@267: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@267: THEN( "frequency detection fails correctly (XTRACT_NO_RESULT is returned, result set to 0.0)" ) jamie@267: { jamie@267: REQUIRE(rv == XTRACT_NO_RESULT); jamie@267: REQUIRE(result == 0.0); jamie@267: } jamie@267: } jamie@268: jamie@268: jamie@267: WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 4 cycles in the block jamie@267: { jamie@267: double frequency = 344.53125; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@267: xtract_f0(table, blocksize, &samplerate, &result); jamie@267: jamie@267: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@267: { jamie@267: actual = xttest_ftom(result); jamie@267: expected = xttest_ftom(frequency); jamie@267: CAPTURE( actual ); jamie@267: CAPTURE( expected ); jamie@267: REQUIRE(actual == expected); jamie@267: } jamie@268: jamie@268: jamie@267: WHEN( "the amplitude is 0.01" ) // Only test a different amplitude for one case jamie@267: { jamie@267: double amplitude = 0.01; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@267: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@267: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@267: { jamie@267: actual = xttest_ftom(result); jamie@267: expected = xttest_ftom(frequency); jamie@267: CAPTURE( actual ); jamie@267: CAPTURE( expected ); jamie@267: REQUIRE(actual == expected); jamie@267: } jamie@267: } jamie@267: } jamie@267: } jamie@268: jamie@264: GIVEN( "a 1024 sample block with a sample rate of 44100" ) jamie@264: { jamie@264: uint32_t blocksize = 1024; jamie@264: double samplerate = 44100; jamie@267: double result = -1.0; jamie@268: double amplitude = 1.0; jamie@268: double table[blocksize]; jamie@268: jamie@268: WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 2 cycles in the block jamie@268: { jamie@268: double frequency = 86.1328125; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@268: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "frequency detection fails correctly (XTRACT_NO_RESULT is returned, result set to 0.0)" ) jamie@268: { jamie@268: REQUIRE(rv == XTRACT_NO_RESULT); jamie@268: REQUIRE(result == 0.0); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "the frequency is 140 Hz" ) // period of 315 samples: 3.25 cycles in the block jamie@268: { jamie@268: double frequency = 140; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: expected = xttest_ftom(frequency); jamie@268: CAPTURE( actual ); jamie@268: CAPTURE( expected ); jamie@268: REQUIRE(actual == expected); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "the frequency is 155 Hz" ) // period of 284.52 samples: 3.6 cycles in the block jamie@268: { jamie@268: double frequency = 155; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is quantized to the nearest whole number of samples" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: expected = xttest_ftom(155.28169014); // period of 284 samples jamie@268: CAPTURE( result ); jamie@268: CAPTURE( expected ); jamie@268: REQUIRE(actual == expected); jamie@268: } jamie@268: } jamie@268: jamie@268: jamie@268: WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 4 cycles in the block jamie@268: { jamie@268: double frequency = 172.265625; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: expected = xttest_ftom(frequency); jamie@268: CAPTURE( actual ); jamie@268: CAPTURE( expected ); jamie@268: REQUIRE(actual == expected); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 8 cycles in the block jamie@268: { jamie@268: double frequency = 344.53125; jamie@268: double noise[blocksize]; jamie@268: expected = xttest_ftom(frequency); jamie@268: CAPTURE( expected ); jamie@268: jamie@268: WHEN( "the amplitude is 1.0" ) jamie@268: { jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: CAPTURE( actual ); jamie@268: REQUIRE(actual == expected); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "the amplitude is 0.01" ) // Only test a different amplitude for one case jamie@268: { jamie@268: amplitude = 0.01; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: CAPTURE( actual ); jamie@268: REQUIRE(actual == expected); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "white noise is added at 10%" ) // Only test noise for one case jamie@268: { jamie@268: amplitude = 0.1; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@268: xttest_gen_noise(noise, blocksize, amplitude); jamie@268: xttest_add(table, noise, blocksize); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: CAPTURE( actual ); jamie@268: REQUIRE(actual == expected); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "white noise is added at 20%" ) jamie@268: { jamie@268: amplitude = 0.2; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@268: xttest_gen_noise(noise, blocksize, amplitude); jamie@268: xttest_add(table, noise, blocksize); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: CAPTURE( actual ); jamie@268: REQUIRE(actual == expected); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "white noise is added at 25%" ) jamie@268: { jamie@268: amplitude = 0.25; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@268: xttest_gen_noise(noise, blocksize, amplitude); jamie@268: xttest_add(table, noise, blocksize); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest semitone" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: uint16_t min = expected - 100; jamie@268: uint16_t max = expected + 100; jamie@268: CAPTURE( actual ); jamie@268: REQUIRE( actual > min ); jamie@268: REQUIRE( actual < max ); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "white noise is added at 30%" ) jamie@268: { jamie@268: amplitude = 0.25; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@268: xttest_gen_noise(noise, blocksize, amplitude); jamie@268: xttest_add(table, noise, blocksize); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: uint16_t min = expected - 50; jamie@268: uint16_t max = expected + 50; jamie@268: CAPTURE( actual ); jamie@268: REQUIRE( actual > min ); jamie@268: REQUIRE( actual < max ); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "white noise is added at 35%" ) jamie@268: { jamie@268: amplitude = 0.35; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@268: xttest_gen_noise(noise, blocksize, amplitude); jamie@268: xttest_add(table, noise, blocksize); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is inaccurate by more than one semitone" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: uint16_t difference = abs(expected - actual); jamie@268: CAPTURE( actual ); jamie@268: REQUIRE( difference > 100 ); jamie@268: } jamie@268: } jamie@268: } jamie@268: } jamie@268: jamie@268: GIVEN( "a 1024 sample block with a sample rate of 11025" ) jamie@268: { jamie@268: uint32_t blocksize = 1024; jamie@268: double samplerate = 11025; jamie@268: double result = -1.0; jamie@264: double table[blocksize]; jamie@264: jamie@267: WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 2 cycles in the block jamie@267: { jamie@267: double frequency = 86.1328125; jamie@267: double amplitude = 1.0; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@267: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@267: { jamie@268: actual = xttest_ftom(result); jamie@268: expected = xttest_ftom(frequency); jamie@268: CAPTURE( actual ); jamie@268: CAPTURE( expected ); jamie@268: REQUIRE(actual == expected); jamie@268: } jamie@267: } jamie@267: jamie@267: WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 4 cycles in the block jamie@267: { jamie@267: double frequency = 172.265625; jamie@267: double amplitude = 1.0; jamie@267: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@267: xtract_f0(table, blocksize, &samplerate, &result); jamie@267: jamie@267: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@267: { jamie@267: actual = xttest_ftom(result); jamie@267: expected = xttest_ftom(frequency); jamie@267: CAPTURE( actual ); jamie@267: CAPTURE( expected ); jamie@267: REQUIRE(actual == expected); jamie@267: } jamie@267: } jamie@267: jamie@267: WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 8 cycles in the block jamie@264: { jamie@264: double frequency = 344.53125; jamie@267: expected = xttest_ftom(frequency); jamie@267: CAPTURE( expected ); jamie@264: jamie@264: WHEN( "the amplitude is 1.0" ) jamie@264: { jamie@264: double amplitude = 1.0; jamie@264: jamie@264: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@264: xtract_f0(table, blocksize, &samplerate, &result); jamie@264: jamie@267: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@264: { jamie@267: actual = xttest_ftom(result); jamie@267: CAPTURE( actual ); jamie@267: REQUIRE(actual == expected); jamie@264: } jamie@264: } jamie@268: jamie@267: WHEN( "the amplitude is 0.01" ) // Only test a different amplitude for one case jamie@264: { jamie@267: double amplitude = 0.01; jamie@264: jamie@264: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@264: xtract_f0(table, blocksize, &samplerate, &result); jamie@264: jamie@267: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@264: { jamie@267: actual = xttest_ftom(result); jamie@267: CAPTURE( actual ); jamie@267: REQUIRE(actual == expected); jamie@267: } jamie@267: } jamie@268: jamie@268: WHEN( "white noise is added at 20%" ) jamie@267: { jamie@268: double amplitude = 0.2; jamie@267: double noise[blocksize]; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@267: xttest_gen_noise(noise, blocksize, amplitude); jamie@267: xttest_add(table, noise, blocksize); jamie@267: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@267: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@267: { jamie@267: actual = xttest_ftom(result); jamie@267: uint16_t min = expected - 50; jamie@267: uint16_t max = expected + 50; jamie@267: CAPTURE( actual ); jamie@267: REQUIRE( actual > min ); jamie@267: REQUIRE( actual < max ); jamie@268: } jamie@267: } jamie@268: jamie@268: WHEN( "white noise is added at 40%" ) jamie@267: { jamie@268: double amplitude = 0.4; jamie@267: double noise[blocksize]; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@267: xttest_gen_noise(noise, blocksize, amplitude); jamie@267: xttest_add(table, noise, blocksize); jamie@267: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest semi-tone" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: uint16_t min = expected - 100; jamie@268: uint16_t max = expected + 100; jamie@268: CAPTURE( actual ); jamie@268: REQUIRE( actual > min ); jamie@268: REQUIRE( actual < max ); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "white noise is added at 60%" ) jamie@268: { jamie@268: double amplitude = 0.6; jamie@268: double noise[blocksize]; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@268: xttest_gen_noise(noise, blocksize, amplitude); jamie@268: xttest_add(table, noise, blocksize); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "the detected F0 is accurate to the nearest semi-tone" ) jamie@268: { jamie@268: actual = xttest_ftom(result); jamie@268: uint16_t min = expected - 100; jamie@268: uint16_t max = expected + 100; jamie@268: CAPTURE( actual ); jamie@268: REQUIRE( actual > min ); jamie@268: REQUIRE( actual < max ); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "white noise is added at 80%" ) jamie@268: { jamie@268: double amplitude = 0.8; jamie@268: double noise[blocksize]; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@268: xttest_gen_noise(noise, blocksize, amplitude); jamie@268: xttest_add(table, noise, blocksize); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@267: THEN( "the detected F0 is inaccurate by more than one semitone" ) jamie@267: { jamie@267: actual = xttest_ftom(result); jamie@267: uint16_t difference = abs(expected - actual); jamie@267: CAPTURE( actual ); jamie@267: REQUIRE( difference > 100 ); jamie@264: } jamie@264: } jamie@264: } jamie@264: } jamie@268: jamie@268: GIVEN( "a 2048 sample block with a sample rate of 44100" ) jamie@267: { jamie@268: uint32_t blocksize = 2048; jamie@268: double samplerate = 44100; jamie@267: double result = -1.0; jamie@267: double table[blocksize]; jamie@268: jamie@268: WHEN( "the frequency is 43.06640625 Hz" ) // period of exactly 256 samples: 2 cycles in the block jamie@268: { jamie@268: double frequency = 43.06640625; jamie@268: double amplitude = 1.0; jamie@268: jamie@268: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@268: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@268: THEN( "frequency detection fails correctly (XTRACT_NO_RESULT is returned, result set to 0.0)" ) jamie@268: { jamie@268: REQUIRE(rv == XTRACT_NO_RESULT); jamie@268: REQUIRE(result == 0.0); jamie@268: } jamie@268: } jamie@268: jamie@268: WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 4 cycles in the block jamie@267: { jamie@267: double frequency = 86.1328125; jamie@267: double amplitude = 1.0; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@267: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@267: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@267: { jamie@267: actual = xttest_ftom(result); jamie@267: expected = xttest_ftom(frequency); jamie@267: CAPTURE( actual ); jamie@267: CAPTURE( expected ); jamie@267: REQUIRE(actual == expected); jamie@267: } jamie@267: } jamie@268: jamie@268: WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 8 cycles in the block jamie@267: { jamie@268: double frequency = 172.265625; jamie@267: double amplitude = 1.0; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@268: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@267: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@267: { jamie@267: actual = xttest_ftom(result); jamie@267: expected = xttest_ftom(frequency); jamie@267: CAPTURE( actual ); jamie@267: CAPTURE( expected ); jamie@267: REQUIRE(actual == expected); jamie@267: } jamie@267: } jamie@268: jamie@267: WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 16 cycles in the block jamie@267: { jamie@267: double frequency = 344.53125; jamie@268: jamie@267: WHEN( "the amplitude is 1.0" ) jamie@267: { jamie@267: double amplitude = 1.0; jamie@268: jamie@267: xttest_gen_sine(table, blocksize, samplerate, frequency, amplitude); jamie@267: xtract_f0(table, blocksize, &samplerate, &result); jamie@268: jamie@267: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@267: { jamie@267: actual = xttest_ftom(result); jamie@267: expected = xttest_ftom(frequency); jamie@267: CAPTURE( actual ); jamie@267: CAPTURE( expected ); jamie@267: REQUIRE(actual == expected); jamie@267: } jamie@268: } jamie@267: } jamie@267: } jamie@264: } jamie@269: jamie@269: SCENARIO( "F0 is correctly detected for a sawtooth wave", "[xtract_f0]" ) jamie@269: { jamie@269: uint16_t expected = 0; jamie@269: uint16_t actual = 0; jamie@269: jamie@269: GIVEN( "a 512 sample block with a sample rate of 44100" ) jamie@269: { jamie@269: uint32_t blocksize = 512; jamie@269: double samplerate = 44100; jamie@269: double result = -1.0; jamie@269: double amplitude = 1.0; jamie@269: double table[blocksize]; jamie@269: jamie@269: WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 1 cycles in the block jamie@269: { jamie@269: double frequency = 86.1328125; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "frequency detection fails correctly (XTRACT_NO_RESULT is returned, result set to 0.0)" ) jamie@269: { jamie@269: REQUIRE(rv == XTRACT_NO_RESULT); jamie@269: REQUIRE(result == 0.0); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 2 cycles in the block jamie@269: { jamie@269: double frequency = 172.265625; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: jamie@269: WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 4 cycles in the block jamie@269: { jamie@269: double frequency = 344.53125; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: jamie@269: jamie@269: WHEN( "the amplitude is 0.01" ) // Only test a different amplitude for one case jamie@269: { jamie@269: double amplitude = 0.01; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: } jamie@269: } jamie@269: jamie@269: GIVEN( "a 1024 sample block with a sample rate of 44100" ) jamie@269: { jamie@269: uint32_t blocksize = 1024; jamie@269: double samplerate = 44100; jamie@269: double result = -1.0; jamie@269: double amplitude = 1.0; jamie@269: double table[blocksize]; jamie@269: jamie@269: WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 2 cycles in the block jamie@269: { jamie@269: double frequency = 86.1328125; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the frequency is 140 Hz" ) // period of 315 samples: 3.25 cycles in the block jamie@269: { jamie@269: double frequency = 140; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE(actual == expected); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the frequency is 155 Hz" ) // period of 284.52 samples: 3.6 cycles in the block jamie@269: { jamie@269: double frequency = 155; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is quantized to the nearest whole number of samples" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(155.28169014); // period of 284 samples jamie@269: CAPTURE( result ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE(actual == expected); jamie@269: } jamie@269: } jamie@269: jamie@269: jamie@269: WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 4 cycles in the block jamie@269: { jamie@269: double frequency = 172.265625; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 8 cycles in the block jamie@269: { jamie@269: double frequency = 344.53125; jamie@269: double noise[blocksize]; jamie@269: expected = xttest_ftom(frequency); jamie@269: CAPTURE( expected ); jamie@269: jamie@269: WHEN( "the amplitude is 1.0" ) jamie@269: { jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the amplitude is 0.01" ) // Only test a different amplitude for one case jamie@269: { jamie@269: amplitude = 0.01; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "white noise is added at 10%" ) // Only test noise for one case jamie@269: { jamie@269: amplitude = 0.1; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@269: xttest_gen_noise(noise, blocksize, amplitude); jamie@269: xttest_add(table, noise, blocksize); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "white noise is added at 20%" ) jamie@269: { jamie@269: amplitude = 0.2; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@269: xttest_gen_noise(noise, blocksize, amplitude); jamie@269: xttest_add(table, noise, blocksize); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "white noise is added at 25%" ) jamie@269: { jamie@269: amplitude = 0.25; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@269: xttest_gen_noise(noise, blocksize, amplitude); jamie@269: xttest_add(table, noise, blocksize); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "white noise is added at 30%" ) jamie@269: { jamie@269: amplitude = 0.25; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@269: xttest_gen_noise(noise, blocksize, amplitude); jamie@269: xttest_add(table, noise, blocksize); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "white noise is added at 35%" ) jamie@269: { jamie@269: amplitude = 0.35; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@269: xttest_gen_noise(noise, blocksize, amplitude); jamie@269: xttest_add(table, noise, blocksize); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: } jamie@269: } jamie@269: jamie@269: GIVEN( "a 1024 sample block with a sample rate of 11025" ) jamie@269: { jamie@269: uint32_t blocksize = 1024; jamie@269: double samplerate = 11025; jamie@269: double result = -1.0; jamie@269: double table[blocksize]; jamie@269: jamie@269: WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 2 cycles in the block jamie@269: { jamie@269: double frequency = 86.1328125; jamie@269: double amplitude = 1.0; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 4 cycles in the block jamie@269: { jamie@269: double frequency = 172.265625; jamie@269: double amplitude = 1.0; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 8 cycles in the block jamie@269: { jamie@269: double frequency = 344.53125; jamie@269: expected = xttest_ftom(frequency); jamie@269: CAPTURE( expected ); jamie@269: jamie@269: WHEN( "the amplitude is 1.0" ) jamie@269: { jamie@269: double amplitude = 1.0; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the amplitude is 0.01" ) // Only test a different amplitude for one case jamie@269: { jamie@269: double amplitude = 0.01; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "white noise is added at 20%" ) jamie@269: { jamie@269: double amplitude = 0.2; jamie@269: double noise[blocksize]; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@269: xttest_gen_noise(noise, blocksize, amplitude); jamie@269: xttest_add(table, noise, blocksize); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "white noise is added at 40%" ) jamie@269: { jamie@269: double amplitude = 0.4; jamie@269: double noise[blocksize]; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, 1.0 - amplitude); jamie@269: xttest_gen_noise(noise, blocksize, amplitude); jamie@269: xttest_add(table, noise, blocksize); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is inaccurate by more than one semitone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: uint16_t difference = abs(expected - actual); jamie@269: CAPTURE( actual ); jamie@269: REQUIRE( difference > 100 ); jamie@269: } jamie@269: } jamie@269: } jamie@269: } jamie@269: jamie@269: GIVEN( "a 2048 sample block with a sample rate of 44100" ) jamie@269: { jamie@269: uint32_t blocksize = 2048; jamie@269: double samplerate = 44100; jamie@269: double result = -1.0; jamie@269: double table[blocksize]; jamie@269: jamie@269: WHEN( "the frequency is 43.06640625 Hz" ) // period of exactly 256 samples: 2 cycles in the block jamie@269: { jamie@269: double frequency = 43.06640625; jamie@269: double amplitude = 1.0; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest quarter-tone" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: uint16_t min = expected - 50; jamie@269: uint16_t max = expected + 50; jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE( actual > min ); jamie@269: REQUIRE( actual < max ); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the frequency is 86.1328125 Hz" ) // period of exactly 512 samples: 4 cycles in the block jamie@269: { jamie@269: double frequency = 86.1328125; jamie@269: double amplitude = 1.0; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: int rv = xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE(actual == expected); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the frequency is 172.265625 Hz" ) // period of exactly 256 samples: 8 cycles in the block jamie@269: { jamie@269: double frequency = 172.265625; jamie@269: double amplitude = 1.0; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE(actual == expected); jamie@269: } jamie@269: } jamie@269: jamie@269: WHEN( "the frequency is 344.53125 Hz" ) // period of exactly 128 samples: 16 cycles in the block jamie@269: { jamie@269: double frequency = 344.53125; jamie@269: jamie@269: WHEN( "the amplitude is 1.0" ) jamie@269: { jamie@269: double amplitude = 1.0; jamie@269: jamie@269: xttest_gen_sawtooth(table, blocksize, samplerate, frequency, amplitude); jamie@269: xtract_f0(table, blocksize, &samplerate, &result); jamie@269: jamie@269: THEN( "the detected F0 is accurate to the nearest MIDI cent" ) jamie@269: { jamie@269: actual = xttest_ftom(result); jamie@269: expected = xttest_ftom(frequency); jamie@269: CAPTURE( actual ); jamie@269: CAPTURE( expected ); jamie@269: REQUIRE(actual == expected); jamie@269: } jamie@269: } jamie@269: } jamie@269: } jamie@269: } jamie@269: