Fix controller iteration / linear interpolation.
authorDavid Robillard <d@drobilla.net>
Fri, 23 Oct 2009 04:24:20 +0000 (04:24 +0000)
committerDavid Robillard <d@drobilla.net>
Fri, 23 Oct 2009 04:24:20 +0000 (04:24 +0000)
Add unit test for controller iteration / linear interpolation.

git-svn-id: svn://localhost/ardour2/branches/3.0@5886 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/evoral/evoral/Parameter.hpp
libs/evoral/src/Sequence.cpp
libs/evoral/test/SequenceTest.cpp
libs/evoral/test/SequenceTest.hpp

index 8ffa5d30c7a03a21515cb04f9253e8e47df29a24..6bd0954b8aa54264ae03a60f08741eac75817361 100644 (file)
@@ -75,7 +75,7 @@ public:
         *    f(x, y) and f(x, z) hold => !f(x, z)
         *
         *    That implies one of the following:
-        *        <ol>
+        *    <ol>
         *      <li> x == z which contradicts the assumption f(x, y) and f(y, x)
         *                 because of antisymmetry.
         *      </li>
index 636816eb69bd02680603fc3fdbe1f271c14f11c5..93eccb6cce000467427d6a691207ab02dbcb3ecc 100644 (file)
@@ -97,7 +97,7 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
        for (Controls::const_iterator i = seq._controls.begin(); i != seq._controls.end(); ++i) {
                DUMP(format("Iterator: control: %1%\n") % seq._type_map.to_symbol(i->first));
                double x, y;
-               bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y);
+               bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y, true);
                if (!ret) {
                        DUMP(format("Iterator: CC %1% (size %2%) has no events past %3%\n")
                                        % i->first.id() % i->second->list()->size() % t);
@@ -128,6 +128,7 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
 
        if (found) {
                _control_iter = _control_iters.begin() + earliest_control_index;
+               assert(_control_iter != _control_iters.end());
        } else {
                _control_iter = _control_iters.end();
        }
@@ -140,14 +141,15 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
                earliest_t = (*_note_iter)->time();
        }
 
-       if (_sysex_iter != seq.sysexes().end() && (*_sysex_iter)->time() < earliest_t) {
+       if (_sysex_iter != seq.sysexes().end()
+                       && ((*_sysex_iter)->time() < earliest_t || _type == NIL)) {
                _type = SYSEX;
                earliest_t = (*_sysex_iter)->time();
        }
 
        if (_control_iter != _control_iters.end()
                        && earliest_control.list && earliest_control.x >= t
-                       && earliest_control.x < earliest_t) {
+                       && (earliest_control.x < earliest_t || _type == NIL)) {
                _type = CONTROL;
                earliest_t = earliest_control.x;
        }
index 0f6a30e5f139030570ac4563c602a402db0c14e4..2c5c17f4d862ffb3b136694de4502f2d684a8a9e 100644 (file)
@@ -1,4 +1,5 @@
 #include "SequenceTest.hpp"
+#include "evoral/MIDIParameters.hpp"
 #include <cassert>
 
 CPPUNIT_TEST_SUITE_REGISTRATION(SequenceTest);
@@ -62,7 +63,6 @@ SequenceTest::preserveEventOrderingTest ()
        CPPUNIT_ASSERT_EQUAL(size_t(12), test_notes.size());
 }
 
-
 void
 SequenceTest::iteratorSeekTest ()
 {
@@ -89,3 +89,68 @@ SequenceTest::iteratorSeekTest ()
 
        CPPUNIT_ASSERT_EQUAL(num_notes, size_t(6));
 }
+
+void
+SequenceTest::controlInterpolationTest ()
+{
+       seq->clear();
+
+       for (Notes::const_iterator i = test_notes.begin(); i != test_notes.end(); ++i) {
+               seq->notes().insert(*i);
+       }
+
+       static const FrameTime delay   = 1000;
+       static const uint32_t  cc_type = 1;
+
+       boost::shared_ptr<Control> c = seq->control(MIDI::ContinuousController(cc_type, 1, 1), true);
+       CPPUNIT_ASSERT(c);
+
+       double min, max, normal;
+       MIDI::controller_range(min, max, normal);
+
+       // Make a ramp like /\ from min to max and back to min
+       c->set_float(min, true, 0);
+       c->set_float(max, true, delay);
+       c->set_float(min, true, 2*delay);
+
+       CCTestSink<Time> sink(cc_type);
+
+       // Test discrete (lack of) interpolation
+       c->list()->set_interpolation(ControlList::Discrete);
+       for (MySequence<Time>::const_iterator i = seq->begin(); i != seq->end(); ++i) {
+               sink.write(i->time(), i->event_type(), i->size(), i->buffer());
+       }
+       CPPUNIT_ASSERT(sink.events.size() == 3);
+       CPPUNIT_ASSERT(sink.events[0].first == 0);
+       CPPUNIT_ASSERT(sink.events[0].second == 0);
+       CPPUNIT_ASSERT(sink.events[1].first == 1000);
+       CPPUNIT_ASSERT(sink.events[1].second == 127);
+       CPPUNIT_ASSERT(sink.events[2].first == 2000);
+       CPPUNIT_ASSERT(sink.events[2].second == 0);
+       sink.events.clear();
+       CPPUNIT_ASSERT(sink.events.size() == 0);
+
+       // Test linear interpolation
+       c->list()->set_interpolation(ControlList::Linear);
+       for (MySequence<Time>::const_iterator i = seq->begin(); i != seq->end(); ++i) {
+               sink.write(i->time(), i->event_type(), i->size(), i->buffer());
+       }
+       CPPUNIT_ASSERT(sink.events.size() == 128 * 2 - 1);
+       Time    last_time  = 0;
+       int16_t last_value = -1;
+       bool    ascending  = true;
+       for (CCTestSink<Time>::Events::const_iterator i = sink.events.begin();
+                       i != sink.events.end(); ++i) {
+               CPPUNIT_ASSERT(last_time == 0 || i->first > last_time);
+               if (last_value == 127) {
+                       ascending = false;
+               }
+               if (ascending) {
+                       CPPUNIT_ASSERT(i->second == last_value + 1);
+               } else {
+                       CPPUNIT_ASSERT(i->second == last_value - 1);
+               }
+               last_time = i->first;
+               last_value = i->second;
+       }
+}
index 8773c3774a698551f5bb8d4faa59075ff62fcb1a..403ac0fd1388d498730e9b26031a376fc740c951 100644 (file)
@@ -12,7 +12,6 @@ using namespace Evoral;
 
 class DummyTypeMap : public TypeMap {
 public:
-
        enum DummyEventType {
                NOTE,
                CONTROL,
@@ -92,12 +91,31 @@ private:
        Time _last_event_time;
 };
 
+template<typename Time>
+class CCTestSink : public EventSink<Time> {
+public:
+       CCTestSink(uint32_t t) : cc_type(t) {}
+
+       virtual uint32_t write(Time time, EventType type, uint32_t size, const uint8_t* buf) {
+               if (type == cc_type) {
+                       CPPUNIT_ASSERT(size == 3);
+                       events.push_back(make_pair(time, buf[2]));
+               }
+               return size;
+       }
+
+       typedef std::vector< std::pair<Time, uint8_t> > Events;
+       Events events;
+       uint32_t cc_type;
+};
+
 class SequenceTest : public CppUnit::TestFixture
 {
        CPPUNIT_TEST_SUITE (SequenceTest);
        CPPUNIT_TEST (createTest);
        CPPUNIT_TEST (preserveEventOrderingTest);
        CPPUNIT_TEST (iteratorSeekTest);
+       CPPUNIT_TEST (controlInterpolationTest);
        CPPUNIT_TEST_SUITE_END ();
 
 public:
@@ -125,6 +143,7 @@ public:
        void createTest ();
        void preserveEventOrderingTest ();
        void iteratorSeekTest ();
+       void controlInterpolationTest ();
 
 private:
        DummyTypeMap*       type_map;