From dde0848a984e06cbc1d4117d9cffa75c191f3b39 Mon Sep 17 00:00:00 2001 From: Sakari Bergen Date: Sun, 27 Dec 2009 14:46:23 +0000 Subject: Re-integrate export-optimization branch. Export now happens directly to file (unless normalizing is required), and can be easily optimized even further. The Session process connection is still broken during export (as it was before this commit also). git-svn-id: svn://localhost/ardour2/branches/3.0@6401 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/audiographer/tests/chunker_test.cc | 112 +++++++++++ libs/audiographer/tests/deinterleaver_test.cc | 133 +++++++++++++ libs/audiographer/tests/identity_vertex_test.cc | 99 ++++++++++ .../tests/interleaver_deinterleaver_test.cc | 120 ++++++++++++ libs/audiographer/tests/interleaver_test.cc | 132 +++++++++++++ libs/audiographer/tests/normalizer_test.cc | 60 ++++++ libs/audiographer/tests/peak_reader_test.cc | 53 ++++++ .../tests/sample_format_converter_test.cc | 209 +++++++++++++++++++++ libs/audiographer/tests/silence_trimmer_test.cc | 196 +++++++++++++++++++ libs/audiographer/tests/sndfile_writer_test.cc | 42 +++++ libs/audiographer/tests/sr_converter_test.cc | 101 ++++++++++ libs/audiographer/tests/test_runner.cc | 14 ++ libs/audiographer/tests/threader_test.cc | 155 +++++++++++++++ libs/audiographer/tests/utils.h | 119 ++++++++++++ 14 files changed, 1545 insertions(+) create mode 100644 libs/audiographer/tests/chunker_test.cc create mode 100644 libs/audiographer/tests/deinterleaver_test.cc create mode 100644 libs/audiographer/tests/identity_vertex_test.cc create mode 100644 libs/audiographer/tests/interleaver_deinterleaver_test.cc create mode 100644 libs/audiographer/tests/interleaver_test.cc create mode 100644 libs/audiographer/tests/normalizer_test.cc create mode 100644 libs/audiographer/tests/peak_reader_test.cc create mode 100644 libs/audiographer/tests/sample_format_converter_test.cc create mode 100644 libs/audiographer/tests/silence_trimmer_test.cc create mode 100644 libs/audiographer/tests/sndfile_writer_test.cc create mode 100644 libs/audiographer/tests/sr_converter_test.cc create mode 100644 libs/audiographer/tests/test_runner.cc create mode 100644 libs/audiographer/tests/threader_test.cc create mode 100644 libs/audiographer/tests/utils.h (limited to 'libs/audiographer/tests') 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 + +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()); + chunker.reset (new Chunker(frames * 2)); + } + + void tearDown() + { + delete [] random_data; + } + + void testSynchronousProcess() + { + chunker->add_output (sink); + nframes_t frames_output = 0; + + ProcessContext 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 const half_context (random_data, frames / 2, 1); + ProcessContext 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; + boost::shared_ptr > 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()); + sink_a.reset (new VectorSink()); + sink_b.reset (new VectorSink()); + sink_c.reset (new VectorSink()); + } + + void tearDown() + { + delete [] random_data; + } + + void testUninitialized() + { + deinterleaver.reset (new DeInterleaver()); + 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 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 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 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; + + boost::shared_ptr > sink_a; + boost::shared_ptr > sink_b; + boost::shared_ptr > 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()); + sink_b.reset (new VectorSink()); + } + + void tearDown() + { + delete [] random_data; + delete [] zero_data; + } + + void testProcess() + { + vertex.reset (new IdentityVertex()); + vertex->add_output (sink_a); + vertex->add_output (sink_b); + + nframes_t frames_output = 0; + + ProcessContext 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()); + vertex->add_output (sink_a); + vertex->add_output (sink_b); + + ProcessContext c (random_data, frames, 1); + vertex->process (c); + + vertex->remove_output (sink_a); + ProcessContext 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()); + vertex->add_output (sink_a); + vertex->add_output (sink_b); + + ProcessContext c (random_data, frames, 1); + vertex->process (c); + + vertex->clear_outputs (); + ProcessContext 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 > vertex; + boost::shared_ptr > sink_a; + boost::shared_ptr > 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()); + interleaver.reset (new Interleaver()); + + sink_a.reset (new VectorSink()); + sink_b.reset (new VectorSink()); + sink_c.reset (new VectorSink()); + } + + 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 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 c_a (random_data_a, frames_per_channel, 1); + ProcessContext c_b (random_data_b, frames_per_channel, 1); + ProcessContext 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; + boost::shared_ptr > deinterleaver; + + boost::shared_ptr > sink_a; + boost::shared_ptr > sink_b; + boost::shared_ptr > 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()); + sink.reset (new VectorSink()); + + interleaver->init (channels, frames); + } + + void tearDown() + { + delete [] random_data; + } + + void testUninitialized() + { + interleaver.reset (new Interleaver()); + ProcessContext c (random_data, frames, 1); + CPPUNIT_ASSERT_THROW (interleaver->input(0)->process (c), Exception); + } + + void testInvalidInputIndex() + { + ProcessContext c (random_data, frames, 1); + CPPUNIT_ASSERT_THROW (interleaver->input (3)->process (c), Exception); + } + + void testInvalidInputSize() + { + ProcessContext 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 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 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 c (random_data, frames, 1); + interleaver->input (0)->process (c); + CPPUNIT_ASSERT_THROW (interleaver->input (0)->process (c), Exception); + } + + + private: + boost::shared_ptr > interleaver; + + boost::shared_ptr > 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()); + + ProcessContext 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 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; + boost::shared_ptr peak_reader; + boost::shared_ptr > 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 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 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 > f_converter (new SampleFormatConverter(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 > i_converter (new SampleFormatConverter(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 > i16_converter (new SampleFormatConverter(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 > ui_converter (new SampleFormatConverter(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 > converter (new SampleFormatConverter(1)); + boost::shared_ptr > sink (new VectorSink()); + + converter->init (frames, D_Tri, 32); + converter->add_output (sink); + nframes_t frames_output = 0; + + { + ProcessContext pc(random_data, frames / 2, 1); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames / 2, frames_output); + } + + { + ProcessContext pc(random_data, frames, 1); + converter->process (pc); + frames_output = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_output); + } + + { + ProcessContext pc(random_data, frames + 1, 1); + CPPUNIT_ASSERT_THROW(converter->process (pc), Exception); + } + } + + void testFloat() + { + boost::shared_ptr > converter (new SampleFormatConverter(1)); + boost::shared_ptr > sink (new VectorSink()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 32); + converter->add_output (sink); + + converter->set_clip_floats (false); + ProcessContext 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 > converter (new SampleFormatConverter(1)); + boost::shared_ptr > sink (new VectorSink()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 32); + converter->add_output (sink); + + ProcessContext 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 > converter (new SampleFormatConverter(1)); + boost::shared_ptr > sink (new VectorSink()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 24); + converter->add_output (sink); + + ProcessContext 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 > converter (new SampleFormatConverter(1)); + boost::shared_ptr > sink (new VectorSink()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 16); + converter->add_output (sink); + + ProcessContext 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 > converter (new SampleFormatConverter(1)); + boost::shared_ptr > sink (new VectorSink()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 8); + converter->add_output (sink); + + ProcessContext 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 > converter (new SampleFormatConverter(3)); + boost::shared_ptr > sink (new VectorSink()); + nframes_t frames_output = 0; + + converter->init(frames, D_Tri, 32); + converter->add_output (sink); + + ProcessContext 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()); + sink.reset (new AppendingVectorSink()); + + 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(frames / 2); + + { + ProcessContext 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 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 c (zero_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames, frames_processed); + } + + { + ProcessContext 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 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(frames / 4); + + { + ProcessContext 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 c (zero_data, frames, 1); + trimmer->process (c); + nframes_t frames_processed = sink->get_data().size(); + CPPUNIT_ASSERT_EQUAL (frames / 2, frames_processed); + } + + { + ProcessContext 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 c (random_data, frames, 1); + trimmer->process (c); + } + + { + ProcessContext c (zero_data, frames, 1); + trimmer->process (c); + } + + { + // Zeros not inited, so this should throw + ProcessContext c (random_data, frames, 1); + CPPUNIT_ASSERT_THROW (trimmer->process (c), Exception); + } + } + + void testAddSilenceBeginning() + { + trimmer->add_output (sink); + AudioGrapher::Utils::init_zeros(frames / 2); + + nframes_t silence = frames / 2; + trimmer->add_silence_to_beginning (silence); + + { + ProcessContext 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(frames / 2); + + nframes_t silence = frames / 3; + trimmer->add_silence_to_end (silence); + + { + ProcessContext c (random_data, frames, 1); + trimmer->process (c); + } + + { + ProcessContext c (random_data, frames, 1); + c.set_flag (ProcessContext::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 > trimmer; + boost::shared_ptr > 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(channels, 44100, SF_FORMAT_WAV | SF_FORMAT_FLOAT, filename)); + ProcessContext c (random_data, frames, channels); + c.set_flag (ProcessContext::EndOfInput); + writer->process (c); + } + + private: + boost::shared_ptr > 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()); + 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 c (random_data, half_frames, 1); + converter->process (c); + ProcessContext c2 (&random_data[half_frames], half_frames, 1); + c2.set_flag (ProcessContext::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 c (random_data, half_frames, 1); + converter->process (c); + ProcessContext c2 (&random_data[half_frames], half_frames, 1); + c2.set_flag (ProcessContext::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 c (random_data, half_frames, 1); + converter->process (c); + ProcessContext c2 (&random_data[half_frames], half_frames, 1); + c2.set_flag (ProcessContext::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 converter; + boost::shared_ptr > 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 +#include + +#include + +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 (*thread_pool)); + + sink_a.reset (new VectorSink()); + sink_b.reset (new VectorSink()); + sink_c.reset (new VectorSink()); + sink_d.reset (new VectorSink()); + sink_e.reset (new VectorSink()); + sink_f.reset (new VectorSink()); + + throwing_sink.reset (new ThrowingSink()); + } + + 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 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 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 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 c (random_data, frames, 1); + threader->process (c); + + threader->clear_outputs(); + ProcessContext 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 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; + boost::shared_ptr > sink_a; + boost::shared_ptr > sink_b; + boost::shared_ptr > sink_c; + boost::shared_ptr > sink_d; + boost::shared_ptr > sink_e; + boost::shared_ptr > sink_f; + + boost::shared_ptr > 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 +#include + +// includes used in this file + +#include "audiographer/sink.h" +#include "audiographer/exception.h" + +#include +#include +#include +#include + +using AudioGrapher::nframes_t; + +struct TestUtils +{ + template + 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 + static bool array_filled (T const * array, nframes_t frames) + { + for (nframes_t i = 0; i < frames; ++i) { + if (array[i] == static_cast (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 +class VectorSink : public AudioGrapher::Sink +{ + public: + virtual void process (AudioGrapher::ProcessContext const & c) + { + data.resize (c.frames()); + memcpy (&data[0], c.data(), c.frames() * sizeof(T)); + } + + void process (AudioGrapher::ProcessContext & c) { AudioGrapher::Sink::process (c); } + using AudioGrapher::Sink::process; + + std::vector const & get_data() const { return data; } + T const * get_array() const { return &data[0]; } + void reset() { data.clear(); } + + protected: + std::vector data; + +}; + +template +class AppendingVectorSink : public VectorSink +{ + public: + void process (AudioGrapher::ProcessContext const & c) + { + std::vector & data (VectorSink::data); + data.resize (total_frames + c.frames()); + memcpy (&data[total_frames], c.data(), c.frames() * sizeof(T)); + total_frames += c.frames(); + } + using AudioGrapher::Sink::process; + + void reset () + { + total_frames = 0; + VectorSink::reset(); + } + + private: + nframes_t total_frames; +}; + + +template +class ThrowingSink : public AudioGrapher::Sink +{ + public: + void process (AudioGrapher::ProcessContext const &) + { + throw AudioGrapher::Exception(*this, "ThrowingSink threw!"); + } + using AudioGrapher::Sink::process; +}; + +#endif // AUDIOGRAPHER_TESTS_UTILS_H -- cgit v1.2.3