mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
It is slightly questionable whether type specific methods like velocity() belong on Event at all, these may be better off as free functions. However the code currently uses them as methods in many places, and it seems like a step in the right direction, since, for example, we might some day have events that have a velocity but aren't stored as MIDI messages (e.g. if Ardour uses an internal musical model that is more expressive). In any case, the former inheritance and plethora of sloppy casts is definitely not the right thing.
156 lines
4.2 KiB
C++
156 lines
4.2 KiB
C++
#include "SequenceTest.hpp"
|
|
#include <cassert>
|
|
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(SequenceTest);
|
|
|
|
using namespace std;
|
|
using namespace Evoral;
|
|
|
|
void
|
|
SequenceTest::createTest ()
|
|
{
|
|
CPPUNIT_ASSERT_EQUAL(size_t(0), seq->sysexes().size());
|
|
CPPUNIT_ASSERT_EQUAL(size_t(0), seq->notes().size());
|
|
CPPUNIT_ASSERT(seq->notes().begin() == seq->notes().end());
|
|
}
|
|
|
|
|
|
void
|
|
SequenceTest::preserveEventOrderingTest ()
|
|
{
|
|
vector< boost::shared_ptr< Event<Time> > > inserted_events;
|
|
|
|
seq->start_write();
|
|
|
|
for (Notes::const_iterator i = test_notes.begin(); i != test_notes.end(); ++i) {
|
|
uint8_t buffer[3];
|
|
Event<Time>* event = new Event<Time>(
|
|
DummyTypeMap::CONTROL, (*i)->on_event().time(), 3, buffer, true
|
|
);
|
|
|
|
event->buffer()[0] = MIDI_CMD_CONTROL;
|
|
event->buffer()[1] = event->time().to_double() / 1000;
|
|
event->buffer()[2] = event->time().to_double() / 1000;
|
|
|
|
boost::shared_ptr<Event<Time> > event_ptr(event);
|
|
|
|
seq->append((*i)->on_event(), next_event_id ());
|
|
inserted_events.push_back(
|
|
boost::shared_ptr<Event<Time> >(
|
|
new Event<Time>((*i)->on_event(), true)
|
|
));
|
|
|
|
seq->append(*event_ptr, next_event_id ());
|
|
inserted_events.push_back(event_ptr);
|
|
|
|
seq->append((*i)->off_event(), next_event_id ());
|
|
inserted_events.push_back(
|
|
boost::shared_ptr<Event<Time> >(
|
|
new Event<Time>((*i)->off_event(), true)
|
|
));
|
|
}
|
|
|
|
seq->end_write (Sequence<Time>::Relax);
|
|
|
|
TestSink<Time> sink;
|
|
sink.writing.connect(sigc::mem_fun(&sink, &TestSink<Time>::assertLastEventTimeEarlier));
|
|
|
|
|
|
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_EQUAL(size_t(12), test_notes.size());
|
|
}
|
|
|
|
void
|
|
SequenceTest::iteratorSeekTest ()
|
|
{
|
|
size_t num_notes = 0;
|
|
|
|
seq->clear();
|
|
|
|
for (Notes::const_iterator i = test_notes.begin(); i != test_notes.end(); ++i) {
|
|
seq->notes().insert(*i);
|
|
}
|
|
|
|
bool on = true;
|
|
for (Sequence<Time>::const_iterator i = seq->begin(Evoral::Beats(600)); i != seq->end(); ++i) {
|
|
if (on) {
|
|
CPPUNIT_ASSERT((*i)->is_note_on());
|
|
CPPUNIT_ASSERT_EQUAL(i->time(), Time((num_notes + 6) * 100));
|
|
++num_notes;
|
|
on = false;
|
|
} else {
|
|
CPPUNIT_ASSERT((*i)->is_note_off());
|
|
on = true;
|
|
}
|
|
}
|
|
|
|
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 uint64_t delay = 1000;
|
|
static const uint32_t cc_type = 1;
|
|
|
|
boost::shared_ptr<Control> c = seq->control(Parameter(cc_type, 1, 1), true);
|
|
CPPUNIT_ASSERT(c);
|
|
|
|
double min = 0.0;
|
|
double max = 127.0;
|
|
|
|
// Make a ramp like /\ from min to max and back to min
|
|
c->set_double(min, 0, true);
|
|
c->set_double(max, delay, true);
|
|
c->set_double(min, 2*delay, true);
|
|
|
|
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;
|
|
}
|
|
}
|