diff options
Diffstat (limited to 'libs/audiographer/tests')
-rw-r--r-- | libs/audiographer/tests/chunker_test.cc | 112 | ||||
-rw-r--r-- | libs/audiographer/tests/deinterleaver_test.cc | 133 | ||||
-rw-r--r-- | libs/audiographer/tests/identity_vertex_test.cc | 99 | ||||
-rw-r--r-- | libs/audiographer/tests/interleaver_deinterleaver_test.cc | 120 | ||||
-rw-r--r-- | libs/audiographer/tests/interleaver_test.cc | 132 | ||||
-rw-r--r-- | libs/audiographer/tests/normalizer_test.cc | 60 | ||||
-rw-r--r-- | libs/audiographer/tests/peak_reader_test.cc | 53 | ||||
-rw-r--r-- | libs/audiographer/tests/sample_format_converter_test.cc | 209 | ||||
-rw-r--r-- | libs/audiographer/tests/silence_trimmer_test.cc | 196 | ||||
-rw-r--r-- | libs/audiographer/tests/sndfile_writer_test.cc | 42 | ||||
-rw-r--r-- | libs/audiographer/tests/sr_converter_test.cc | 101 | ||||
-rw-r--r-- | libs/audiographer/tests/test_runner.cc | 14 | ||||
-rw-r--r-- | libs/audiographer/tests/threader_test.cc | 155 | ||||
-rw-r--r-- | libs/audiographer/tests/utils.h | 119 |
14 files changed, 1545 insertions, 0 deletions
diff --git a/libs/audiographer/tests/chunker_test.cc b/libs/audiographer/tests/chunker_test.cc new file mode 100644 index 0000000000..ab0c04d7f9 --- /dev/null +++ b/libs/audiographer/tests/chunker_test.cc @@ -0,0 +1,112 @@ +#include "utils.h" +#include "audiographer/chunker.h" + +#include <cassert> + +using namespace AudioGrapher; + +class ChunkerTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (ChunkerTest); + CPPUNIT_TEST (testSynchronousProcess); + CPPUNIT_TEST (testAsynchronousProcess); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + frames = 128; + random_data = TestUtils::init_random_data(frames); + sink.reset (new VectorSink<float>()); + chunker.reset (new Chunker<float>(frames * 2)); + } + + void tearDown() + { + delete [] random_data; + } + + void testSynchronousProcess() + { + chunker->add_output (sink); + nframes_t frames_output = 0; + + ProcessContext<float> const context (random_data, frames, 1); + + chunker->process (context); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output); + + chunker->process (context); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames], frames)); + + sink->reset(); + + chunker->process (context); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output); + + chunker->process (context); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames], frames)); + } + + void testAsynchronousProcess() + { + assert (frames % 2 == 0); + + chunker->add_output (sink); + nframes_t frames_output = 0; + + ProcessContext<float> const half_context (random_data, frames / 2, 1); + ProcessContext<float> const context (random_data, frames, 1); + + // 0.5 + chunker->process (half_context); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output); + + // 1.5 + chunker->process (context); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output); + + // 2.5 + chunker->process (context); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames / 2)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames / 2], frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[ 3 * frames / 2], frames / 2)); + + sink->reset(); + + // 3.5 + chunker->process (context); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output); + + // 4.0 + chunker->process (half_context); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_equals (&random_data[frames / 2], sink->get_array(), frames / 2)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames / 2], frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[ 3 * frames / 2], frames / 2)); + } + + private: + boost::shared_ptr<Chunker<float> > chunker; + boost::shared_ptr<VectorSink<float> > sink; + + float * random_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (ChunkerTest); + diff --git a/libs/audiographer/tests/deinterleaver_test.cc b/libs/audiographer/tests/deinterleaver_test.cc new file mode 100644 index 0000000000..b0adbc0444 --- /dev/null +++ b/libs/audiographer/tests/deinterleaver_test.cc @@ -0,0 +1,133 @@ +#include "utils.h" +#include "audiographer/deinterleaver.h" + +using namespace AudioGrapher; + +class DeInterleaverTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (DeInterleaverTest); + CPPUNIT_TEST (testUninitialized); + CPPUNIT_TEST (testInvalidOutputIndex); + CPPUNIT_TEST (testInvalidInputSize); + CPPUNIT_TEST (testOutputSize); + CPPUNIT_TEST (testZeroInput); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + channels = 3; + frames_per_channel = 128; + total_frames = channels * frames_per_channel; + random_data = TestUtils::init_random_data (total_frames, 1.0); + + deinterleaver.reset (new DeInterleaver<float>()); + sink_a.reset (new VectorSink<float>()); + sink_b.reset (new VectorSink<float>()); + sink_c.reset (new VectorSink<float>()); + } + + void tearDown() + { + delete [] random_data; + } + + void testUninitialized() + { + deinterleaver.reset (new DeInterleaver<float>()); + CPPUNIT_ASSERT_THROW (deinterleaver->output(0)->add_output (sink_a), Exception); + } + + void testInvalidOutputIndex() + { + deinterleaver->init (3, frames_per_channel); + CPPUNIT_ASSERT_THROW (deinterleaver->output(3)->add_output (sink_a), Exception); + } + + void testInvalidInputSize() + { + deinterleaver->init (channels, frames_per_channel); + + ProcessContext<float> c (random_data, 0, channels); + + // Too many, frames % channels == 0 + c.frames() = total_frames + channels; + CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception); + + // Too many, frames % channels != 0 + c.frames() = total_frames + 1; + CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception); + + // Too few, frames % channels != 0 + c.frames() = total_frames - 1; + CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception); + } + + void assert_outputs (nframes_t expected_frames) + { + nframes_t generated_frames = 0; + + generated_frames = sink_a->get_data().size(); + CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames); + + generated_frames = sink_b->get_data().size(); + CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames); + + generated_frames = sink_c->get_data().size(); + CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames); + } + + void testOutputSize() + { + deinterleaver->init (channels, frames_per_channel); + + deinterleaver->output (0)->add_output (sink_a); + deinterleaver->output (1)->add_output (sink_b); + deinterleaver->output (2)->add_output (sink_c); + + // Test maximum frame input + ProcessContext<float> c (random_data, total_frames, channels); + deinterleaver->process (c); + assert_outputs (frames_per_channel); + + // Now with less frames + nframes_t const less_frames = frames_per_channel / 4; + c.frames() = less_frames * channels; + deinterleaver->process (c); + assert_outputs (less_frames); + } + + void testZeroInput() + { + deinterleaver->init (channels, frames_per_channel); + + deinterleaver->output (0)->add_output (sink_a); + deinterleaver->output (1)->add_output (sink_b); + deinterleaver->output (2)->add_output (sink_c); + + // Input zero frames + ProcessContext<float> c (random_data, 0, channels); + deinterleaver->process (c); + + // ...and now test regular input + c.frames() = total_frames; + deinterleaver->process (c); + assert_outputs (frames_per_channel); + } + + + private: + boost::shared_ptr<DeInterleaver<float> > deinterleaver; + + boost::shared_ptr<VectorSink<float> > sink_a; + boost::shared_ptr<VectorSink<float> > sink_b; + boost::shared_ptr<VectorSink<float> > sink_c; + + float * random_data; + nframes_t frames_per_channel; + nframes_t total_frames; + unsigned int channels; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (DeInterleaverTest); + diff --git a/libs/audiographer/tests/identity_vertex_test.cc b/libs/audiographer/tests/identity_vertex_test.cc new file mode 100644 index 0000000000..5a3ae7c9f2 --- /dev/null +++ b/libs/audiographer/tests/identity_vertex_test.cc @@ -0,0 +1,99 @@ +#include "utils.h" +#include "audiographer/identity_vertex.h" + +using namespace AudioGrapher; + +class IdentityVertexTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (IdentityVertexTest); + CPPUNIT_TEST (testProcess); + CPPUNIT_TEST (testRemoveOutput); + CPPUNIT_TEST (testClearOutputs); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + frames = 128; + random_data = TestUtils::init_random_data(frames); + + zero_data = new float[frames]; + memset (zero_data, 0, frames * sizeof(float)); + + sink_a.reset (new VectorSink<float>()); + sink_b.reset (new VectorSink<float>()); + } + + void tearDown() + { + delete [] random_data; + delete [] zero_data; + } + + void testProcess() + { + vertex.reset (new IdentityVertex<float>()); + vertex->add_output (sink_a); + vertex->add_output (sink_b); + + nframes_t frames_output = 0; + + ProcessContext<float> c (random_data, frames, 1); + vertex->process (c); + + frames_output = sink_a->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + + frames_output = sink_b->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_a->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_b->get_array(), frames)); + } + + void testRemoveOutput() + { + vertex.reset (new IdentityVertex<float>()); + vertex->add_output (sink_a); + vertex->add_output (sink_b); + + ProcessContext<float> c (random_data, frames, 1); + vertex->process (c); + + vertex->remove_output (sink_a); + ProcessContext<float> zc (zero_data, frames, 1); + vertex->process (zc); + + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_a->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (zero_data, sink_b->get_array(), frames)); + } + + void testClearOutputs() + { + vertex.reset (new IdentityVertex<float>()); + vertex->add_output (sink_a); + vertex->add_output (sink_b); + + ProcessContext<float> c (random_data, frames, 1); + vertex->process (c); + + vertex->clear_outputs (); + ProcessContext<float> zc (zero_data, frames, 1); + vertex->process (zc); + + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_a->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_b->get_array(), frames)); + } + + private: + boost::shared_ptr<IdentityVertex<float> > vertex; + boost::shared_ptr<VectorSink<float> > sink_a; + boost::shared_ptr<VectorSink<float> > sink_b; + + float * random_data; + float * zero_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (IdentityVertexTest); + diff --git a/libs/audiographer/tests/interleaver_deinterleaver_test.cc b/libs/audiographer/tests/interleaver_deinterleaver_test.cc new file mode 100644 index 0000000000..5655253e62 --- /dev/null +++ b/libs/audiographer/tests/interleaver_deinterleaver_test.cc @@ -0,0 +1,120 @@ +#include "utils.h" +#include "audiographer/interleaver.h" +#include "audiographer/deinterleaver.h" + +using namespace AudioGrapher; + +class InterleaverDeInterleaverTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (InterleaverDeInterleaverTest); + CPPUNIT_TEST (testInterleavedInput); + CPPUNIT_TEST (testDeInterleavedInput); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + channels = 3; + frames_per_channel = 128; + total_frames = channels * frames_per_channel; + + random_data_a = TestUtils::init_random_data (total_frames, 1.0); + random_data_b = TestUtils::init_random_data (frames_per_channel, 1.0); + random_data_c = TestUtils::init_random_data (frames_per_channel, 1.0); + + deinterleaver.reset (new DeInterleaver<float>()); + interleaver.reset (new Interleaver<float>()); + + sink_a.reset (new VectorSink<float>()); + sink_b.reset (new VectorSink<float>()); + sink_c.reset (new VectorSink<float>()); + } + + void tearDown() + { + delete [] random_data_a; + delete [] random_data_b; + delete [] random_data_c; + } + + void testInterleavedInput() + { + deinterleaver->init (channels, frames_per_channel); + interleaver->init (channels, frames_per_channel); + + deinterleaver->output (0)->add_output (interleaver->input (0)); + deinterleaver->output (1)->add_output (interleaver->input (1)); + deinterleaver->output (2)->add_output (interleaver->input (2)); + + interleaver->add_output (sink_a); + + // Process and assert + ProcessContext<float> c (random_data_a, total_frames, channels); + deinterleaver->process (c); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), total_frames)); + + // And a second round... + nframes_t less_frames = (frames_per_channel / 10) * channels; + c.frames() = less_frames; + deinterleaver->process (c); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), less_frames)); + } + + void testDeInterleavedInput() + { + deinterleaver->init (channels, frames_per_channel); + interleaver->init (channels, frames_per_channel); + + interleaver->add_output (deinterleaver); + + deinterleaver->output (0)->add_output (sink_a); + deinterleaver->output (1)->add_output (sink_b); + deinterleaver->output (2)->add_output (sink_c); + + ProcessContext<float> c_a (random_data_a, frames_per_channel, 1); + ProcessContext<float> c_b (random_data_b, frames_per_channel, 1); + ProcessContext<float> c_c (random_data_c, frames_per_channel, 1); + + // Process and assert + interleaver->input (0)->process (c_a); + interleaver->input (1)->process (c_b); + interleaver->input (2)->process (c_c); + + CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), frames_per_channel)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data_b, sink_b->get_array(), frames_per_channel)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data_c, sink_c->get_array(), frames_per_channel)); + + // And a second round... + nframes_t less_frames = frames_per_channel / 5; + c_a.frames() = less_frames; + c_b.frames() = less_frames; + c_c.frames() = less_frames; + interleaver->input (0)->process (c_a); + interleaver->input (1)->process (c_b); + interleaver->input (2)->process (c_c); + + CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), less_frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data_b, sink_b->get_array(), less_frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (random_data_c, sink_c->get_array(), less_frames)); + + } + + private: + boost::shared_ptr<Interleaver<float> > interleaver; + boost::shared_ptr<DeInterleaver<float> > deinterleaver; + + boost::shared_ptr<VectorSink<float> > sink_a; + boost::shared_ptr<VectorSink<float> > sink_b; + boost::shared_ptr<VectorSink<float> > sink_c; + + float * random_data_a; + float * random_data_b; + float * random_data_c; + + nframes_t frames_per_channel; + nframes_t total_frames; + unsigned int channels; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (InterleaverDeInterleaverTest); + diff --git a/libs/audiographer/tests/interleaver_test.cc b/libs/audiographer/tests/interleaver_test.cc new file mode 100644 index 0000000000..abe385699d --- /dev/null +++ b/libs/audiographer/tests/interleaver_test.cc @@ -0,0 +1,132 @@ +#include "utils.h" +#include "audiographer/interleaver.h" + +using namespace AudioGrapher; + +class InterleaverTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (InterleaverTest); + CPPUNIT_TEST (testUninitialized); + CPPUNIT_TEST (testInvalidInputIndex); + CPPUNIT_TEST (testInvalidInputSize); + CPPUNIT_TEST (testOutputSize); + CPPUNIT_TEST (testZeroInput); + CPPUNIT_TEST (testChannelSync); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + channels = 3; + frames = 128; + random_data = TestUtils::init_random_data (frames, 1.0); + + interleaver.reset (new Interleaver<float>()); + sink.reset (new VectorSink<float>()); + + interleaver->init (channels, frames); + } + + void tearDown() + { + delete [] random_data; + } + + void testUninitialized() + { + interleaver.reset (new Interleaver<float>()); + ProcessContext<float> c (random_data, frames, 1); + CPPUNIT_ASSERT_THROW (interleaver->input(0)->process (c), Exception); + } + + void testInvalidInputIndex() + { + ProcessContext<float> c (random_data, frames, 1); + CPPUNIT_ASSERT_THROW (interleaver->input (3)->process (c), Exception); + } + + void testInvalidInputSize() + { + ProcessContext<float> c (random_data, frames + 1, 1); + CPPUNIT_ASSERT_THROW (interleaver->input (0)->process (c), Exception); + + c.frames() = frames; + interleaver->input (0)->process (c); + interleaver->input (1)->process (c); + c.frames() = frames -1; + CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c), Exception); + + interleaver->input (0)->process (c); + interleaver->input (1)->process (c); + c.frames() = frames; + CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c), Exception); + } + + void testOutputSize() + { + interleaver->add_output (sink); + + ProcessContext<float> c (random_data, frames, 1); + interleaver->input (0)->process (c); + interleaver->input (1)->process (c); + interleaver->input (2)->process (c); + + nframes_t expected_frames = frames * channels; + nframes_t generated_frames = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames); + + nframes_t less_frames = frames / 2; + c.frames() = less_frames; + interleaver->input (0)->process (c); + interleaver->input (1)->process (c); + interleaver->input (2)->process (c); + + expected_frames = less_frames * channels; + generated_frames = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames); + } + + void testZeroInput() + { + interleaver->add_output (sink); + + // input zero frames to all inputs + ProcessContext<float> c (random_data, 0, 1); + interleaver->input (0)->process (c); + interleaver->input (1)->process (c); + interleaver->input (2)->process (c); + + // NOTE zero input is allowed to be a NOP + + // ...now test regular input + c.frames() = frames; + interleaver->input (0)->process (c); + interleaver->input (1)->process (c); + interleaver->input (2)->process (c); + + nframes_t expected_frames = frames * channels; + nframes_t generated_frames = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames); + } + + void testChannelSync() + { + interleaver->add_output (sink); + ProcessContext<float> c (random_data, frames, 1); + interleaver->input (0)->process (c); + CPPUNIT_ASSERT_THROW (interleaver->input (0)->process (c), Exception); + } + + + private: + boost::shared_ptr<Interleaver<float> > interleaver; + + boost::shared_ptr<VectorSink<float> > sink; + + nframes_t channels; + float * random_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (InterleaverTest); + diff --git a/libs/audiographer/tests/normalizer_test.cc b/libs/audiographer/tests/normalizer_test.cc new file mode 100644 index 0000000000..711e0018ca --- /dev/null +++ b/libs/audiographer/tests/normalizer_test.cc @@ -0,0 +1,60 @@ +#include "utils.h" + +#include "audiographer/normalizer.h" +#include "audiographer/peak_reader.h" + +using namespace AudioGrapher; + +class NormalizerTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (NormalizerTest); + CPPUNIT_TEST (testConstAmplify); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + frames = 1024; + } + + void tearDown() + { + delete [] random_data; + } + + void testConstAmplify() + { + float target = 0.0; + random_data = TestUtils::init_random_data(frames, 0.5); + + normalizer.reset (new Normalizer(target)); + peak_reader.reset (new PeakReader()); + sink.reset (new VectorSink<float>()); + + ProcessContext<float> const c (random_data, frames, 1); + peak_reader->process (c); + + float peak = peak_reader->get_peak(); + normalizer->alloc_buffer (frames); + normalizer->set_peak (peak); + normalizer->add_output (sink); + normalizer->process (c); + + peak_reader->reset(); + ConstProcessContext<float> normalized (sink->get_array(), frames, 1); + peak_reader->process (normalized); + + peak = peak_reader->get_peak(); + CPPUNIT_ASSERT (-FLT_EPSILON <= (peak - 1.0) && (peak - 1.0) <= 0.0); + } + + private: + boost::shared_ptr<Normalizer> normalizer; + boost::shared_ptr<PeakReader> peak_reader; + boost::shared_ptr<VectorSink<float> > sink; + + float * random_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (NormalizerTest); diff --git a/libs/audiographer/tests/peak_reader_test.cc b/libs/audiographer/tests/peak_reader_test.cc new file mode 100644 index 0000000000..dce03b6caf --- /dev/null +++ b/libs/audiographer/tests/peak_reader_test.cc @@ -0,0 +1,53 @@ +#include "utils.h" +#include "audiographer/peak_reader.h" + +using namespace AudioGrapher; + +class PeakReaderTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (PeakReaderTest); + CPPUNIT_TEST (testProcess); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + frames = 128; + random_data = TestUtils::init_random_data(frames); + } + + void tearDown() + { + delete [] random_data; + } + + void testProcess() + { + reader.reset (new PeakReader()); + ProcessContext<float> c (random_data, frames, 1); + + float peak = 1.5; + random_data[10] = peak; + reader->process (c); + CPPUNIT_ASSERT_EQUAL(peak, reader->get_peak()); + + peak = 2.0; + random_data[10] = peak; + reader->process (c); + CPPUNIT_ASSERT_EQUAL(peak, reader->get_peak()); + + peak = -2.1; + random_data[10] = peak; + reader->process (c); + float expected = fabs(peak); + CPPUNIT_ASSERT_EQUAL(expected, reader->get_peak()); + } + + private: + boost::shared_ptr<PeakReader> reader; + + float * random_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (PeakReaderTest); diff --git a/libs/audiographer/tests/sample_format_converter_test.cc b/libs/audiographer/tests/sample_format_converter_test.cc new file mode 100644 index 0000000000..f723f7af53 --- /dev/null +++ b/libs/audiographer/tests/sample_format_converter_test.cc @@ -0,0 +1,209 @@ +#include "utils.h" +#include "audiographer/sample_format_converter.h" + +using namespace AudioGrapher; + +class SampleFormatConverterTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (SampleFormatConverterTest); + CPPUNIT_TEST (testInit); + CPPUNIT_TEST (testFrameCount); + CPPUNIT_TEST (testFloat); + CPPUNIT_TEST (testInt32); + CPPUNIT_TEST (testInt24); + CPPUNIT_TEST (testInt16); + CPPUNIT_TEST (testUint8); + CPPUNIT_TEST (testChannelCount); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + frames = 128; + random_data = TestUtils::init_random_data(frames, 1.0); + } + + void tearDown() + { + delete [] random_data; + } + + void testInit() + { + boost::shared_ptr<SampleFormatConverter<float> > f_converter (new SampleFormatConverter<float>(1)); + f_converter->init (frames, D_Tri, 32); // Doesn't throw + CPPUNIT_ASSERT_THROW (f_converter->init (frames, D_Tri, 24), Exception); + CPPUNIT_ASSERT_THROW (f_converter->init (frames, D_Tri, 48), Exception); + + boost::shared_ptr<SampleFormatConverter<int32_t> > i_converter (new SampleFormatConverter<int32_t>(1)); + i_converter->init (frames, D_Tri, 32); // Doesn't throw + i_converter->init (frames, D_Tri, 24); // Doesn't throw + CPPUNIT_ASSERT_THROW (i_converter->init (frames, D_Tri, 8), Exception); + CPPUNIT_ASSERT_THROW (i_converter->init (frames, D_Tri, 16), Exception); + CPPUNIT_ASSERT_THROW (i_converter->init (frames, D_Tri, 48), Exception); + + boost::shared_ptr<SampleFormatConverter<int16_t> > i16_converter (new SampleFormatConverter<int16_t>(1)); + i16_converter->init (frames, D_Tri, 16); // Doesn't throw + CPPUNIT_ASSERT_THROW (i16_converter->init (frames, D_Tri, 8), Exception); + CPPUNIT_ASSERT_THROW (i16_converter->init (frames, D_Tri, 32), Exception); + CPPUNIT_ASSERT_THROW (i16_converter->init (frames, D_Tri, 48), Exception); + + boost::shared_ptr<SampleFormatConverter<uint8_t> > ui_converter (new SampleFormatConverter<uint8_t>(1)); + ui_converter->init (frames, D_Tri, 8); // Doesn't throw + CPPUNIT_ASSERT_THROW (ui_converter->init (frames, D_Tri, 4), Exception); + CPPUNIT_ASSERT_THROW (ui_converter->init (frames, D_Tri, 16), Exception); + } + + void testFrameCount() + { + boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(1)); + boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>()); + + converter->init (frames, D_Tri, 32); + converter->add_output (sink); + nframes_t frames_output = 0; + + { + ProcessContext<float> pc(random_data, frames / 2, 1); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames / 2, frames_output); + } + + { + ProcessContext<float> pc(random_data, frames, 1); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + } + + { + ProcessContext<float> pc(random_data, frames + 1, 1); + CPPUNIT_ASSERT_THROW(converter->process (pc), Exception); + } + } + + void testFloat() + { + boost::shared_ptr<SampleFormatConverter<float> > converter (new SampleFormatConverter<float>(1)); + boost::shared_ptr<VectorSink<float> > sink (new VectorSink<float>()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 32); + converter->add_output (sink); + + converter->set_clip_floats (false); + ProcessContext<float> const pc(random_data, frames, 1); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_equals(sink->get_array(), random_data, frames)); + + // Make sure a few samples are < -1.0 and > 1.0 + random_data[10] = -1.5; + random_data[20] = 1.5; + + converter->set_clip_floats (true); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames)); + + for (nframes_t i = 0; i < frames; ++i) { + // fp comparison needs a bit of tolerance, 1.01 << 1.5 + CPPUNIT_ASSERT(sink->get_data()[i] < 1.01); + CPPUNIT_ASSERT(sink->get_data()[i] > -1.01); + } + } + + void testInt32() + { + boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(1)); + boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 32); + converter->add_output (sink); + + ProcessContext<float> pc(random_data, frames, 1); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames)); + } + + void testInt24() + { + boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(1)); + boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 24); + converter->add_output (sink); + + ProcessContext<float> pc(random_data, frames, 1); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames)); + } + + void testInt16() + { + boost::shared_ptr<SampleFormatConverter<int16_t> > converter (new SampleFormatConverter<int16_t>(1)); + boost::shared_ptr<VectorSink<int16_t> > sink (new VectorSink<int16_t>()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 16); + converter->add_output (sink); + + ProcessContext<float> pc(random_data, frames, 1); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames)); + } + + void testUint8() + { + boost::shared_ptr<SampleFormatConverter<uint8_t> > converter (new SampleFormatConverter<uint8_t>(1)); + boost::shared_ptr<VectorSink<uint8_t> > sink (new VectorSink<uint8_t>()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 8); + converter->add_output (sink); + + ProcessContext<float> pc(random_data, frames, 1); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames)); + } + + void testChannelCount() + { + boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(3)); + boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 32); + converter->add_output (sink); + + ProcessContext<float> pc(random_data, 4, 1); + CPPUNIT_ASSERT_THROW (converter->process (pc), Exception); + + pc.frames() = frames - (frames % 3); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (pc.frames(), frames_output); + CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), pc.frames())); + } + + private: + + float * random_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (SampleFormatConverterTest); + diff --git a/libs/audiographer/tests/silence_trimmer_test.cc b/libs/audiographer/tests/silence_trimmer_test.cc new file mode 100644 index 0000000000..16234bec37 --- /dev/null +++ b/libs/audiographer/tests/silence_trimmer_test.cc @@ -0,0 +1,196 @@ +#include "utils.h" + +#include "audiographer/silence_trimmer.h" + +using namespace AudioGrapher; + +class SilenceTrimmerTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (SilenceTrimmerTest); + CPPUNIT_TEST (testExceptions); + CPPUNIT_TEST (testFullBuffers); + CPPUNIT_TEST (testPartialBuffers); + CPPUNIT_TEST (testAddSilenceBeginning); + CPPUNIT_TEST (testAddSilenceEnd); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + frames = 128; + + random_data = TestUtils::init_random_data(frames); + random_data[0] = 0.5; + random_data[frames - 1] = 0.5; + + zero_data = new float[frames]; + memset(zero_data, 0, frames * sizeof(float)); + + half_random_data = TestUtils::init_random_data(frames); + memset(half_random_data, 0, (frames / 2) * sizeof(float)); + + trimmer.reset (new SilenceTrimmer<float>()); + sink.reset (new AppendingVectorSink<float>()); + + trimmer->set_trim_beginning (true); + trimmer->set_trim_end (true); + } + + void tearDown() + { + delete [] random_data; + delete [] zero_data; + delete [] half_random_data; + + AudioGrapher::Utils::free_resources(); + } + + void testFullBuffers() + { + trimmer->add_output (sink); + AudioGrapher::Utils::init_zeros<float>(frames / 2); + + { + ProcessContext<float> c (zero_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_processed); + } + + { + ProcessContext<float> c (random_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_processed); + CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), random_data, frames)); + } + + { + ProcessContext<float> c (zero_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_processed); + } + + { + ProcessContext<float> c (random_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (3 * frames, frames_processed); + CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), random_data, frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames], zero_data, frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[2 * frames], random_data, frames)); + } + + { + ProcessContext<float> c (zero_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (3 * frames, frames_processed); + } + } + + void testPartialBuffers() + { + trimmer->add_output (sink); + AudioGrapher::Utils::init_zeros<float>(frames / 4); + + { + ProcessContext<float> c (half_random_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames / 2, frames_processed); + CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), &half_random_data[frames / 2], frames / 2)); + } + + { + ProcessContext<float> c (zero_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames / 2, frames_processed); + } + + { + ProcessContext<float> c (half_random_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (2 * frames + frames / 2, frames_processed); + CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames + frames / 2], half_random_data, frames)); + } + } + + void testExceptions() + { + // TODO more tests here + + trimmer->add_output (sink); + + { + ProcessContext<float> c (random_data, frames, 1); + trimmer->process (c); + } + + { + ProcessContext<float> c (zero_data, frames, 1); + trimmer->process (c); + } + + { + // Zeros not inited, so this should throw + ProcessContext<float> c (random_data, frames, 1); + CPPUNIT_ASSERT_THROW (trimmer->process (c), Exception); + } + } + + void testAddSilenceBeginning() + { + trimmer->add_output (sink); + AudioGrapher::Utils::init_zeros<float>(frames / 2); + + nframes_t silence = frames / 2; + trimmer->add_silence_to_beginning (silence); + + { + ProcessContext<float> c (random_data, frames, 1); + trimmer->process (c); + } + + CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), zero_data, silence)); + CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[silence], random_data, frames)); + } + + void testAddSilenceEnd() + { + trimmer->add_output (sink); + AudioGrapher::Utils::init_zeros<float>(frames / 2); + + nframes_t silence = frames / 3; + trimmer->add_silence_to_end (silence); + + { + ProcessContext<float> c (random_data, frames, 1); + trimmer->process (c); + } + + { + ProcessContext<float> c (random_data, frames, 1); + c.set_flag (ProcessContext<float>::EndOfInput); + trimmer->process (c); + } + + CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), random_data, frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames], random_data, frames)); + CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames * 2], zero_data, silence)); + } + + private: + boost::shared_ptr<SilenceTrimmer<float> > trimmer; + boost::shared_ptr<AppendingVectorSink<float> > sink; + + float * random_data; + float * zero_data; + float * half_random_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (SilenceTrimmerTest); diff --git a/libs/audiographer/tests/sndfile_writer_test.cc b/libs/audiographer/tests/sndfile_writer_test.cc new file mode 100644 index 0000000000..359d456f15 --- /dev/null +++ b/libs/audiographer/tests/sndfile_writer_test.cc @@ -0,0 +1,42 @@ +#include "utils.h" +#include "audiographer/sndfile_writer.h" + +using namespace AudioGrapher; + +class SndfileWriterTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (SndfileWriterTest); + CPPUNIT_TEST (testProcess); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + frames = 128; + random_data = TestUtils::init_random_data(frames); + } + + void tearDown() + { + delete [] random_data; + } + + void testProcess() + { + uint channels = 2; + std::string filename ("test.wav"); + writer.reset (new SndfileWriter<float>(channels, 44100, SF_FORMAT_WAV | SF_FORMAT_FLOAT, filename)); + ProcessContext<float> c (random_data, frames, channels); + c.set_flag (ProcessContext<float>::EndOfInput); + writer->process (c); + } + + private: + boost::shared_ptr<SndfileWriter<float> > writer; + + float * random_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (SndfileWriterTest); + diff --git a/libs/audiographer/tests/sr_converter_test.cc b/libs/audiographer/tests/sr_converter_test.cc new file mode 100644 index 0000000000..59c05806c6 --- /dev/null +++ b/libs/audiographer/tests/sr_converter_test.cc @@ -0,0 +1,101 @@ +#include "utils.h" +#include "audiographer/sr_converter.h" + +using namespace AudioGrapher; + +class SampleRateConverterTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (SampleRateConverterTest); + CPPUNIT_TEST (testNoConversion); + CPPUNIT_TEST (testUpsampleLength); + CPPUNIT_TEST (testDownsampleLength); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + frames = 128; + random_data = TestUtils::init_random_data(frames); + sink.reset (new AppendingVectorSink<float>()); + converter.reset (new SampleRateConverter (1)); + } + + void tearDown() + { + delete [] random_data; + } + + void testNoConversion() + { + assert (frames % 2 == 0); + nframes_t const half_frames = frames / 2; + nframes_t frames_output = 0; + + converter->init (44100, 44100); + converter->add_output (sink); + + ProcessContext<float> c (random_data, half_frames, 1); + converter->process (c); + ProcessContext<float> c2 (&random_data[half_frames], half_frames, 1); + c2.set_flag (ProcessContext<float>::EndOfInput); + converter->process (c2); + + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + + CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames)); + } + + void testUpsampleLength() + { + assert (frames % 2 == 0); + nframes_t const half_frames = frames / 2; + nframes_t frames_output = 0; + + converter->init (44100, 88200); + converter->allocate_buffers (half_frames); + converter->add_output (sink); + + ProcessContext<float> c (random_data, half_frames, 1); + converter->process (c); + ProcessContext<float> c2 (&random_data[half_frames], half_frames, 1); + c2.set_flag (ProcessContext<float>::EndOfInput); + converter->process (c2); + + frames_output = sink->get_data().size(); + nframes_t tolerance = 3; + CPPUNIT_ASSERT (2 * frames - tolerance < frames_output && frames_output < 2 * frames + tolerance); + } + + void testDownsampleLength() + { + assert (frames % 2 == 0); + nframes_t const half_frames = frames / 2; + nframes_t frames_output = 0; + + converter->init (88200, 44100); + converter->allocate_buffers (half_frames); + converter->add_output (sink); + + ProcessContext<float> c (random_data, half_frames, 1); + converter->process (c); + ProcessContext<float> c2 (&random_data[half_frames], half_frames, 1); + c2.set_flag (ProcessContext<float>::EndOfInput); + converter->process (c2); + + frames_output = sink->get_data().size(); + nframes_t tolerance = 3; + CPPUNIT_ASSERT (half_frames - tolerance < frames_output && frames_output < half_frames + tolerance); + } + + + private: + boost::shared_ptr<SampleRateConverter > converter; + boost::shared_ptr<AppendingVectorSink<float> > sink; + + float * random_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (SampleRateConverterTest); + diff --git a/libs/audiographer/tests/test_runner.cc b/libs/audiographer/tests/test_runner.cc new file mode 100644 index 0000000000..6fed393dc8 --- /dev/null +++ b/libs/audiographer/tests/test_runner.cc @@ -0,0 +1,14 @@ +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <cppunit/ui/text/TestRunner.h> + +#include <glibmm/thread.h> + +int main() +{ + Glib::thread_init(); + CppUnit::TextUi::TestRunner runner; + CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + runner.addTest (registry.makeTest()); + runner.run(); + return 0; +} diff --git a/libs/audiographer/tests/threader_test.cc b/libs/audiographer/tests/threader_test.cc new file mode 100644 index 0000000000..ac5588d79c --- /dev/null +++ b/libs/audiographer/tests/threader_test.cc @@ -0,0 +1,155 @@ +#include "utils.h" +#include "audiographer/threader.h" + +using namespace AudioGrapher; + +class ThreaderTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE (ThreaderTest); + CPPUNIT_TEST (testProcess); + CPPUNIT_TEST (testRemoveOutput); + CPPUNIT_TEST (testClearOutputs); + CPPUNIT_TEST (testExceptions); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp() + { + frames = 128; + random_data = TestUtils::init_random_data (frames, 1.0); + + zero_data = new float[frames]; + memset (zero_data, 0, frames * sizeof(float)); + + thread_pool = new Glib::ThreadPool (3); + threader.reset (new Threader<float> (*thread_pool)); + + sink_a.reset (new VectorSink<float>()); + sink_b.reset (new VectorSink<float>()); + sink_c.reset (new VectorSink<float>()); + sink_d.reset (new VectorSink<float>()); + sink_e.reset (new VectorSink<float>()); + sink_f.reset (new VectorSink<float>()); + + throwing_sink.reset (new ThrowingSink<float>()); + } + + void tearDown() + { + delete [] random_data; + delete [] zero_data; + + thread_pool->shutdown(); + delete thread_pool; + } + + void testProcess() + { + threader->add_output (sink_a); + threader->add_output (sink_b); + threader->add_output (sink_c); + threader->add_output (sink_d); + threader->add_output (sink_e); + threader->add_output (sink_f); + + ProcessContext<float> c (random_data, frames, 1); + threader->process (c); + + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_c->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_d->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_e->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_f->get_array(), frames)); + } + + void testRemoveOutput() + { + threader->add_output (sink_a); + threader->add_output (sink_b); + threader->add_output (sink_c); + threader->add_output (sink_d); + threader->add_output (sink_e); + threader->add_output (sink_f); + + ProcessContext<float> c (random_data, frames, 1); + threader->process (c); + + // Remove a, b and f + threader->remove_output (sink_a); + threader->remove_output (sink_b); + threader->remove_output (sink_f); + + ProcessContext<float> zc (zero_data, frames, 1); + threader->process (zc); + + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(zero_data, sink_c->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(zero_data, sink_d->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(zero_data, sink_e->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_f->get_array(), frames)); + } + + void testClearOutputs() + { + threader->add_output (sink_a); + threader->add_output (sink_b); + threader->add_output (sink_c); + threader->add_output (sink_d); + threader->add_output (sink_e); + threader->add_output (sink_f); + + ProcessContext<float> c (random_data, frames, 1); + threader->process (c); + + threader->clear_outputs(); + ProcessContext<float> zc (zero_data, frames, 1); + threader->process (zc); + + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_c->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_d->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_e->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_f->get_array(), frames)); + } + + void testExceptions() + { + threader->add_output (sink_a); + threader->add_output (sink_b); + threader->add_output (sink_c); + threader->add_output (throwing_sink); + threader->add_output (sink_e); + threader->add_output (throwing_sink); + + ProcessContext<float> c (random_data, frames, 1); + CPPUNIT_ASSERT_THROW (threader->process (c), Exception); + + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_c->get_array(), frames)); + CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_e->get_array(), frames)); + } + + private: + Glib::ThreadPool * thread_pool; + + boost::shared_ptr<Threader<float> > threader; + boost::shared_ptr<VectorSink<float> > sink_a; + boost::shared_ptr<VectorSink<float> > sink_b; + boost::shared_ptr<VectorSink<float> > sink_c; + boost::shared_ptr<VectorSink<float> > sink_d; + boost::shared_ptr<VectorSink<float> > sink_e; + boost::shared_ptr<VectorSink<float> > sink_f; + + boost::shared_ptr<ThrowingSink<float> > throwing_sink; + + float * random_data; + float * zero_data; + nframes_t frames; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (ThreaderTest); + diff --git a/libs/audiographer/tests/utils.h b/libs/audiographer/tests/utils.h new file mode 100644 index 0000000000..6b6a1fea0f --- /dev/null +++ b/libs/audiographer/tests/utils.h @@ -0,0 +1,119 @@ +#ifndef AUDIOGRAPHER_TESTS_UTILS_H +#define AUDIOGRAPHER_TESTS_UTILS_H + +// Includes we want almost always + +#include <cppunit/extensions/HelperMacros.h> +#include <boost/shared_ptr.hpp> + +// includes used in this file + +#include "audiographer/sink.h" +#include "audiographer/exception.h" + +#include <vector> +#include <cstring> +#include <cstdlib> +#include <ctime> + +using AudioGrapher::nframes_t; + +struct TestUtils +{ + template<typename T> + static bool array_equals (T const * a, T const * b, nframes_t frames) + { + for (nframes_t i = 0; i < frames; ++i) { + if (a[i] != b[i]) { + return false; + } + } + return true; + } + + template<typename T> + static bool array_filled (T const * array, nframes_t frames) + { + for (nframes_t i = 0; i < frames; ++i) { + if (array[i] == static_cast<T> (0.0)) { + return false; + } + } + return true; + } + + /// Generate random data, all samples guaranteed not to be 0.0, 1.0 or -1.0 + static float * init_random_data (nframes_t frames, float range = 1.0) + { + unsigned int const granularity = 4096; + float * data = new float[frames]; + srand (std::time (NULL)); + + for (nframes_t i = 0; i < frames; ++i) { + do { + int biased_int = (rand() % granularity) - (granularity / 2); + data[i] = (range * biased_int) / granularity; + } while (data[i] == 0.0 || data[i] == 1.0 || data[i] == -1.0); + } + return data; + } +}; + +template<typename T> +class VectorSink : public AudioGrapher::Sink<T> +{ + public: + virtual void process (AudioGrapher::ProcessContext<T> const & c) + { + data.resize (c.frames()); + memcpy (&data[0], c.data(), c.frames() * sizeof(T)); + } + + void process (AudioGrapher::ProcessContext<T> & c) { AudioGrapher::Sink<T>::process (c); } + using AudioGrapher::Sink<T>::process; + + std::vector<T> const & get_data() const { return data; } + T const * get_array() const { return &data[0]; } + void reset() { data.clear(); } + + protected: + std::vector<T> data; + +}; + +template<typename T> +class AppendingVectorSink : public VectorSink<T> +{ + public: + void process (AudioGrapher::ProcessContext<T> const & c) + { + std::vector<T> & data (VectorSink<T>::data); + data.resize (total_frames + c.frames()); + memcpy (&data[total_frames], c.data(), c.frames() * sizeof(T)); + total_frames += c.frames(); + } + using AudioGrapher::Sink<T>::process; + + void reset () + { + total_frames = 0; + VectorSink<T>::reset(); + } + + private: + nframes_t total_frames; +}; + + +template<typename T> +class ThrowingSink : public AudioGrapher::Sink<T> +{ + public: + void process (AudioGrapher::ProcessContext<T> const &) + { + throw AudioGrapher::Exception(*this, "ThrowingSink threw!"); + } + using AudioGrapher::Sink<T>::process; +}; + +#endif // AUDIOGRAPHER_TESTS_UTILS_H |