You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
5.7KB

  1. #include "MidiEvent.h"
  2. #include "MidiLock.h"
  3. #include "MidiPlayer.h"
  4. #include "MidiSong.h"
  5. #include "MidiTrack.h"
  6. #include "asserts.h"
  7. static void testLock()
  8. {
  9. MidiLock l;
  10. assert(!l.locked());
  11. bool b = l.playerTryLock();
  12. assert(b);
  13. assert(l.locked());
  14. l.playerUnlock();
  15. assert(!l.locked());
  16. l.editorLock();
  17. assert(l.locked());
  18. b = l.playerTryLock();
  19. assert(!b);
  20. l.editorUnlock();
  21. assert(!l.locked());
  22. b = l.playerTryLock();
  23. assert(b);
  24. assert(l.locked());
  25. l.playerUnlock();
  26. assert(!l.locked());
  27. }
  28. static void testLock2()
  29. {
  30. MidiLockPtr l = MidiLock::make();
  31. assert(!l->locked());
  32. bool b = l->playerTryLock();
  33. assert(b);
  34. assert(l->locked());
  35. l->playerUnlock();
  36. assert(!l->locked());
  37. {
  38. MidiLocker _(l);
  39. assert(l->locked());
  40. b = l->playerTryLock();
  41. assert(!b);
  42. }
  43. assert(!l->locked());
  44. b = l->playerTryLock();
  45. assert(b);
  46. assert(l->locked());
  47. l->playerUnlock();
  48. assert(!l->locked());
  49. }
  50. static void testLock3()
  51. {
  52. MidiLockPtr l = MidiLock::make();
  53. l->editorLock();
  54. l->editorLock();
  55. assert(l->locked());
  56. l->editorUnlock();
  57. assert(l->locked());
  58. l->editorUnlock();
  59. assert(!l->locked());
  60. }
  61. static void testLock4()
  62. {
  63. MidiLockPtr l = MidiLock::make();
  64. assert(!l->dataModelDirty());
  65. l->editorLock();
  66. l->editorUnlock();
  67. assert(l->dataModelDirty());
  68. assert(!l->dataModelDirty());
  69. }
  70. class TestHost : public IPlayerHost
  71. {
  72. public:
  73. void setGate(bool g) override
  74. {
  75. if (g != gateState) {
  76. ++gateChangeCount;
  77. gateState = g;
  78. }
  79. }
  80. void setCV(float cv) override
  81. {
  82. if (cv != cvState) {
  83. ++cvChangeCount;
  84. cvState = cv;
  85. }
  86. }
  87. void onLockFailed() override
  88. {
  89. ++lockConflicts;
  90. }
  91. int cvChangeCount = 0;
  92. int gateChangeCount = 0;
  93. bool gateState = false;
  94. float cvState = -100;
  95. int lockConflicts = 0;
  96. };
  97. // test that apis can be called
  98. static void test0()
  99. {
  100. MidiSongPtr song = MidiSong::makeTest(MidiTrack::TestContent::eightQNotes, 0);
  101. std::shared_ptr<TestHost> host = std::make_shared<TestHost>();
  102. MidiPlayer pl(host, song);
  103. pl.timeElapsed(.01f);
  104. }
  105. /**
  106. * Makes a one-track song.
  107. * Track has one quarter note at t=0, duration = eighth.
  108. * End event at quarter note end.
  109. *
  110. * noteOnTime = 0 * .5;
  111. * noteOffTime = .5 * .5;
  112. */
  113. static MidiSongPtr makeSongOneQ()
  114. {
  115. MidiSongPtr song = std::make_shared<MidiSong>();
  116. MidiLocker l(song->lock);
  117. song->createTrack(0);
  118. MidiTrackPtr track = song->getTrack(0);
  119. MidiNoteEventPtr note = std::make_shared<MidiNoteEvent>();
  120. note->startTime = 0;
  121. note->duration = .5;
  122. note->pitchCV = 2.f;
  123. track->insertEvent(note);
  124. track->insertEnd(1);
  125. return song;
  126. }
  127. std::shared_ptr<TestHost> makeSongOneQandRun(float time)
  128. {
  129. MidiSongPtr song = makeSongOneQ();
  130. std::shared_ptr<TestHost> host = std::make_shared<TestHost>();
  131. MidiPlayer pl(host, song);
  132. pl.timeElapsed(time);
  133. return host;
  134. }
  135. std::shared_ptr<TestHost> makeSongOneQandRun2(float timeBeforeLock, float timeDuringLock, float timeAfterLock)
  136. {
  137. MidiSongPtr song = makeSongOneQ();
  138. std::shared_ptr<TestHost> host = std::make_shared<TestHost>();
  139. MidiPlayer pl(host, song);
  140. pl.timeElapsed(timeBeforeLock);
  141. {
  142. MidiLocker l(song->lock);
  143. pl.timeElapsed(timeDuringLock);
  144. }
  145. pl.timeElapsed(timeAfterLock);
  146. return host;
  147. }
  148. // just play the first note on
  149. static void test1()
  150. {
  151. std::shared_ptr<TestHost> host = makeSongOneQandRun(.24f);
  152. assertEQ(host->lockConflicts, 0);
  153. assertEQ(host->gateChangeCount, 1);
  154. assertEQ(host->gateState, true);
  155. assertEQ(host->cvChangeCount, 1);
  156. assertEQ(host->cvState, 2);
  157. assertEQ(host->lockConflicts, 0);
  158. }
  159. // same as test1, but with a lock contention
  160. static void test1L()
  161. {
  162. std::shared_ptr<TestHost> host = makeSongOneQandRun2(.20f, .01f, .03f);
  163. assertEQ(host->gateChangeCount, 1);
  164. assertEQ(host->gateState, true);
  165. assertEQ(host->cvChangeCount, 1);
  166. assertEQ(host->cvState, 2);
  167. assertEQ(host->lockConflicts, 1);
  168. }
  169. // play the first note on and off
  170. static void test2()
  171. {
  172. std::shared_ptr<TestHost> host = makeSongOneQandRun(.25f);
  173. assertEQ(host->lockConflicts, 0);
  174. assertEQ(host->gateChangeCount, 2);
  175. assertEQ(host->gateState, false);
  176. assertEQ(host->cvChangeCount, 1);
  177. assertEQ(host->cvState, 2);
  178. }
  179. // play the first note on and off
  180. static void test2L()
  181. {
  182. std::shared_ptr<TestHost> host = makeSongOneQandRun2(.20f, .01f, .04f);
  183. assertEQ(host->lockConflicts, 1);
  184. assertEQ(host->gateChangeCount, 2);
  185. assertEQ(host->gateState, false);
  186. assertEQ(host->cvChangeCount, 1);
  187. assertEQ(host->cvState, 2);
  188. }
  189. // loop around to first note on second time
  190. static void test3()
  191. {
  192. std::shared_ptr<TestHost> host = makeSongOneQandRun(.51f);
  193. assertEQ(host->gateChangeCount, 3);
  194. assertEQ(host->gateState, true);
  195. assertEQ(host->cvChangeCount, 1); // only changes once because it's one note loop
  196. assertEQ(host->cvState, 2);
  197. }
  198. // loop around to first note on second time
  199. static void test3L()
  200. {
  201. std::shared_ptr<TestHost> host = makeSongOneQandRun2(.4f, .7f, .4f );
  202. assertGE(host->gateChangeCount, 3);
  203. assertEQ(host->gateState, true);
  204. assertGE(host->cvChangeCount, 1); // only changes once because it's one note loop
  205. assertEQ(host->cvState, 2);
  206. }
  207. void testMidiPlayer()
  208. {
  209. assertNoMidi();
  210. testLock();
  211. testLock2();
  212. testLock3();
  213. testLock4();
  214. test0();
  215. test1();
  216. test2();
  217. test3();
  218. test1L();
  219. test2L();
  220. test3L();
  221. assertNoMidi(); // check for leaks
  222. }