#include "MidiEvent.h" #include "MidiLock.h" #include "MidiPlayer.h" #include "MidiSong.h" #include "MidiTrack.h" #include "asserts.h" static void testLock() { MidiLock l; assert(!l.locked()); bool b = l.playerTryLock(); assert(b); assert(l.locked()); l.playerUnlock(); assert(!l.locked()); l.editorLock(); assert(l.locked()); b = l.playerTryLock(); assert(!b); l.editorUnlock(); assert(!l.locked()); b = l.playerTryLock(); assert(b); assert(l.locked()); l.playerUnlock(); assert(!l.locked()); } static void testLock2() { MidiLockPtr l = MidiLock::make(); assert(!l->locked()); bool b = l->playerTryLock(); assert(b); assert(l->locked()); l->playerUnlock(); assert(!l->locked()); { MidiLocker _(l); assert(l->locked()); b = l->playerTryLock(); assert(!b); } assert(!l->locked()); b = l->playerTryLock(); assert(b); assert(l->locked()); l->playerUnlock(); assert(!l->locked()); } static void testLock3() { MidiLockPtr l = MidiLock::make(); l->editorLock(); l->editorLock(); assert(l->locked()); l->editorUnlock(); assert(l->locked()); l->editorUnlock(); assert(!l->locked()); } static void testLock4() { MidiLockPtr l = MidiLock::make(); assert(!l->dataModelDirty()); l->editorLock(); l->editorUnlock(); assert(l->dataModelDirty()); assert(!l->dataModelDirty()); } class TestHost : public IPlayerHost { public: void setGate(bool g) override { if (g != gateState) { ++gateChangeCount; gateState = g; } } void setCV(float cv) override { if (cv != cvState) { ++cvChangeCount; cvState = cv; } } void onLockFailed() override { ++lockConflicts; } int cvChangeCount = 0; int gateChangeCount = 0; bool gateState = false; float cvState = -100; int lockConflicts = 0; }; // test that apis can be called static void test0() { MidiSongPtr song = MidiSong::makeTest(MidiTrack::TestContent::eightQNotes, 0); std::shared_ptr host = std::make_shared(); MidiPlayer pl(host, song); pl.timeElapsed(.01f); } /** * Makes a one-track song. * Track has one quarter note at t=0, duration = eighth. * End event at quarter note end. * * noteOnTime = 0 * .5; * noteOffTime = .5 * .5; */ static MidiSongPtr makeSongOneQ() { MidiSongPtr song = std::make_shared(); MidiLocker l(song->lock); song->createTrack(0); MidiTrackPtr track = song->getTrack(0); MidiNoteEventPtr note = std::make_shared(); note->startTime = 0; note->duration = .5; note->pitchCV = 2.f; track->insertEvent(note); track->insertEnd(1); return song; } std::shared_ptr makeSongOneQandRun(float time) { MidiSongPtr song = makeSongOneQ(); std::shared_ptr host = std::make_shared(); MidiPlayer pl(host, song); pl.timeElapsed(time); return host; } std::shared_ptr makeSongOneQandRun2(float timeBeforeLock, float timeDuringLock, float timeAfterLock) { MidiSongPtr song = makeSongOneQ(); std::shared_ptr host = std::make_shared(); MidiPlayer pl(host, song); pl.timeElapsed(timeBeforeLock); { MidiLocker l(song->lock); pl.timeElapsed(timeDuringLock); } pl.timeElapsed(timeAfterLock); return host; } // just play the first note on static void test1() { std::shared_ptr host = makeSongOneQandRun(.24f); assertEQ(host->lockConflicts, 0); assertEQ(host->gateChangeCount, 1); assertEQ(host->gateState, true); assertEQ(host->cvChangeCount, 1); assertEQ(host->cvState, 2); assertEQ(host->lockConflicts, 0); } // same as test1, but with a lock contention static void test1L() { std::shared_ptr host = makeSongOneQandRun2(.20f, .01f, .03f); assertEQ(host->gateChangeCount, 1); assertEQ(host->gateState, true); assertEQ(host->cvChangeCount, 1); assertEQ(host->cvState, 2); assertEQ(host->lockConflicts, 1); } // play the first note on and off static void test2() { std::shared_ptr host = makeSongOneQandRun(.25f); assertEQ(host->lockConflicts, 0); assertEQ(host->gateChangeCount, 2); assertEQ(host->gateState, false); assertEQ(host->cvChangeCount, 1); assertEQ(host->cvState, 2); } // play the first note on and off static void test2L() { std::shared_ptr host = makeSongOneQandRun2(.20f, .01f, .04f); assertEQ(host->lockConflicts, 1); assertEQ(host->gateChangeCount, 2); assertEQ(host->gateState, false); assertEQ(host->cvChangeCount, 1); assertEQ(host->cvState, 2); } // loop around to first note on second time static void test3() { std::shared_ptr host = makeSongOneQandRun(.51f); assertEQ(host->gateChangeCount, 3); assertEQ(host->gateState, true); assertEQ(host->cvChangeCount, 1); // only changes once because it's one note loop assertEQ(host->cvState, 2); } // loop around to first note on second time static void test3L() { std::shared_ptr host = makeSongOneQandRun2(.4f, .7f, .4f ); assertGE(host->gateChangeCount, 3); assertEQ(host->gateState, true); assertGE(host->cvChangeCount, 1); // only changes once because it's one note loop assertEQ(host->cvState, 2); } void testMidiPlayer() { assertNoMidi(); testLock(); testLock2(); testLock3(); testLock4(); test0(); test1(); test2(); test3(); test1L(); test2L(); test3L(); assertNoMidi(); // check for leaks }