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.

249 lines
7.0KB

  1. #include "asserts.h"
  2. #include "MidiEvent.h"
  3. #include "MidiLock.h"
  4. #include "MidiTrack.h"
  5. #include "MidiSequencer.h"
  6. #include "MidiSong.h"
  7. #include "ReplaceDataCommand.h"
  8. #include "UndoRedoStack.h"
  9. // test that functions can be called
  10. static void test0()
  11. {
  12. UndoRedoStackPtr ur(std::make_shared<UndoRedoStack>());
  13. MidiSongPtr song(std::make_shared<MidiSong>());
  14. MidiSelectionModelPtr selection = std::make_shared<MidiSelectionModel>();
  15. MidiEditorContextPtr context = std::make_shared<MidiEditorContext>(song);
  16. std::vector<MidiEventPtr> toRem;
  17. std::vector<MidiEventPtr> toAdd;
  18. song->createTrack(0);
  19. CommandPtr cmd = std::make_shared<ReplaceDataCommand>(song, selection, context, 0, toRem, toAdd);
  20. ur->execute(cmd);
  21. }
  22. // Test simple add note command
  23. static void test1()
  24. {
  25. UndoRedoStackPtr ur(std::make_shared<UndoRedoStack>());
  26. MidiSongPtr ms(std::make_shared<MidiSong>());
  27. MidiSelectionModelPtr selection = std::make_shared<MidiSelectionModel>();
  28. MidiEditorContextPtr context = std::make_shared<MidiEditorContext>(ms);
  29. ms->createTrack(0);
  30. std::vector<MidiEventPtr> toRem;
  31. std::vector<MidiEventPtr> toAdd;
  32. MidiNoteEventPtr newNote = std::make_shared<MidiNoteEvent>();
  33. assert(newNote);
  34. newNote->pitchCV = 12;
  35. toAdd.push_back(newNote);
  36. CommandPtr cmd = std::make_shared<ReplaceDataCommand>(ms, selection, context, 0, toRem, toAdd);
  37. ur->execute(cmd);
  38. assert(ms->getTrack(0)->size() == 1); // we added an event
  39. assert(ur->canUndo());
  40. auto tv = ms->getTrack(0)->_testGetVector();
  41. assert(*tv[0] == *newNote);
  42. ur->undo();
  43. assert(ms->getTrack(0)->size() == 0); // we added an event
  44. assert(!ur->canUndo());
  45. assert(ur->canRedo());
  46. ur->redo();
  47. assert(ms->getTrack(0)->size() == 1);
  48. }
  49. // Test simple remove note command
  50. static void test2()
  51. {
  52. UndoRedoStackPtr ur(std::make_shared<UndoRedoStack>());
  53. MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::eightQNotes, 0);
  54. MidiSelectionModelPtr selection = std::make_shared<MidiSelectionModel>();
  55. MidiEditorContextPtr context = std::make_shared<MidiEditorContext>(ms);
  56. std::vector<MidiEventPtr> toRem;
  57. std::vector<MidiEventPtr> toAdd;
  58. MidiTrackPtr track = ms->getTrack(0);
  59. const int origSize = track->size();
  60. // MidiEventPtr noteToDelete = track->begin()->second;
  61. // assert(noteToDelete);
  62. auto noteToDelete = track->getFirstNote();
  63. toRem.push_back(noteToDelete);
  64. CommandPtr cmd = std::make_shared<ReplaceDataCommand>(ms, selection, context, 0, toRem, toAdd);
  65. ur->execute(cmd);
  66. assertEQ(ms->getTrack(0)->size(), (origSize - 1)); // we removed an event
  67. assert(ur->canUndo());
  68. ur->undo();
  69. assert(ms->getTrack(0)->size() == origSize); // we added an event
  70. assert(!ur->canUndo());
  71. }
  72. static void testTrans()
  73. {
  74. MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::eightQNotes, 0);
  75. MidiSequencerPtr seq = std::make_shared<MidiSequencer>(ms);
  76. seq->makeEditor();
  77. seq->assertValid();
  78. // MidiEventPtr firstEvent = seq->context->getTrack()->begin()->second;
  79. MidiEventPtr firstEvent = seq->context->getTrack()->getFirstNote();
  80. assert(firstEvent);
  81. seq->selection->select(firstEvent);
  82. auto cmd = ReplaceDataCommand::makeChangePitchCommand(seq, 1);
  83. cmd->execute();
  84. firstEvent = seq->context->getTrack()->begin()->second;
  85. float pitch = safe_cast<MidiNoteEvent>(firstEvent)->pitchCV;
  86. assertClose(pitch, -.91666, .01);
  87. seq->assertValid();
  88. cmd->undo();
  89. seq->assertValid();
  90. cmd->execute();
  91. seq->assertValid();
  92. }
  93. static void testInsert()
  94. {
  95. MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::empty, 0);
  96. MidiLocker l(ms->lock);
  97. MidiSequencerPtr seq = std::make_shared<MidiSequencer>(ms);
  98. seq->makeEditor();
  99. seq->assertValid();
  100. assertEQ(seq->context->getTrack()->size(), 1); // just an end event
  101. MidiNoteEventPtr note = std::make_shared<MidiNoteEvent>();
  102. note->startTime = 100;
  103. note->pitchCV = 1.1f;
  104. note->duration = 2;
  105. auto cmd = ReplaceDataCommand::makeInsertNoteCommand(seq, note);
  106. cmd->execute();
  107. seq->assertValid();
  108. assertEQ(seq->context->getTrack()->size(), 2);
  109. auto ev = seq->context->getTrack()->begin()->second;
  110. MidiNoteEventPtrC note2 = safe_cast<MidiNoteEvent>(ev);
  111. assert(note2);
  112. assert(*note2 == *note);
  113. ev = (++seq->context->getTrack()->begin())->second;
  114. MidiEndEventPtr end = safe_cast<MidiEndEvent>(ev);
  115. assert(end);
  116. // quantize to even bars
  117. int x = (100 + 2) / 4;
  118. x *= 4;
  119. assert(x < 102);
  120. x += 8; // and round up two bars
  121. assertEQ(end->startTime, x);
  122. // assert(false); // undo and redo
  123. printf("add tests for insert note undo/redo\n");
  124. }
  125. static void testStartTime()
  126. {
  127. // make empty song
  128. MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::empty, 0);
  129. MidiLocker l(ms->lock);
  130. MidiSequencerPtr seq = std::make_shared<MidiSequencer>(ms);
  131. seq->makeEditor();
  132. seq->assertValid();
  133. // put a note into it at time 100;
  134. auto track = seq->context->getTrack();
  135. MidiNoteEventPtr note = std::make_shared<MidiNoteEvent>();
  136. note->startTime = 100;
  137. note->pitchCV = 1.1f;
  138. note->duration = 2;
  139. auto cmd = ReplaceDataCommand::makeInsertNoteCommand(seq, note);
  140. cmd->execute();
  141. seq->assertValid();
  142. assertEQ(seq->selection->size(), 1);
  143. // shift note later to 1100
  144. cmd = ReplaceDataCommand::makeChangeStartTimeCommand(seq, 1000.f);
  145. seq->undo->execute(cmd);
  146. seq->assertValid();
  147. note = track->getFirstNote();
  148. assertEQ(note->startTime, 1100.f);
  149. seq->undo->undo();
  150. seq->assertValid();
  151. note = track->getFirstNote();
  152. assertEQ(note->startTime, 100.f);
  153. seq->undo->redo();
  154. seq->assertValid();
  155. note = track->getFirstNote();
  156. assertEQ(note->startTime, 1100.f);
  157. }
  158. static void testDuration()
  159. {
  160. MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::empty, 0);
  161. MidiLocker l(ms->lock);
  162. MidiSequencerPtr seq = std::make_shared<MidiSequencer>(ms);
  163. seq->makeEditor();
  164. seq->assertValid();
  165. // put a note into it at time 10, dur 5;
  166. auto track = seq->context->getTrack();
  167. MidiNoteEventPtr note = std::make_shared<MidiNoteEvent>();
  168. note->startTime = 10;
  169. note->pitchCV = 1.1f;
  170. note->duration = 5;
  171. auto cmd = ReplaceDataCommand::makeInsertNoteCommand(seq, note);
  172. cmd->execute();
  173. seq->assertValid();
  174. // now increase dur by 1
  175. cmd = ReplaceDataCommand::makeChangeDurationCommand(seq, 1.f);
  176. seq->undo->execute(cmd);
  177. seq->assertValid();
  178. note = track->getFirstNote();
  179. assert(note);
  180. assertEQ(note->startTime, 10.f);
  181. assertEQ(note->duration, 6.f)
  182. seq->undo->undo();
  183. seq->assertValid();
  184. note = track->getFirstNote();
  185. assertEQ(note->duration, 5.f);
  186. seq->undo->redo();
  187. seq->assertValid();
  188. note = track->getFirstNote();
  189. assertEQ(note->duration, 6.f);
  190. }
  191. void testReplaceCommand()
  192. {
  193. test0();
  194. test1();
  195. test2();
  196. testTrans();
  197. testInsert();
  198. testStartTime();
  199. testDuration();
  200. }