#include "asserts.h" #include "MidiEvent.h" #include "MidiLock.h" #include "MidiTrack.h" #include "MidiSequencer.h" #include "MidiSong.h" #include "ReplaceDataCommand.h" #include "UndoRedoStack.h" // test that functions can be called static void test0() { UndoRedoStackPtr ur(std::make_shared()); MidiSongPtr song(std::make_shared()); MidiSelectionModelPtr selection = std::make_shared(); MidiEditorContextPtr context = std::make_shared(song); std::vector toRem; std::vector toAdd; song->createTrack(0); CommandPtr cmd = std::make_shared(song, selection, context, 0, toRem, toAdd); ur->execute(cmd); } // Test simple add note command static void test1() { UndoRedoStackPtr ur(std::make_shared()); MidiSongPtr ms(std::make_shared()); MidiSelectionModelPtr selection = std::make_shared(); MidiEditorContextPtr context = std::make_shared(ms); ms->createTrack(0); std::vector toRem; std::vector toAdd; MidiNoteEventPtr newNote = std::make_shared(); assert(newNote); newNote->pitchCV = 12; toAdd.push_back(newNote); CommandPtr cmd = std::make_shared(ms, selection, context, 0, toRem, toAdd); ur->execute(cmd); assert(ms->getTrack(0)->size() == 1); // we added an event assert(ur->canUndo()); auto tv = ms->getTrack(0)->_testGetVector(); assert(*tv[0] == *newNote); ur->undo(); assert(ms->getTrack(0)->size() == 0); // we added an event assert(!ur->canUndo()); assert(ur->canRedo()); ur->redo(); assert(ms->getTrack(0)->size() == 1); } // Test simple remove note command static void test2() { UndoRedoStackPtr ur(std::make_shared()); MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::eightQNotes, 0); MidiSelectionModelPtr selection = std::make_shared(); MidiEditorContextPtr context = std::make_shared(ms); std::vector toRem; std::vector toAdd; MidiTrackPtr track = ms->getTrack(0); const int origSize = track->size(); // MidiEventPtr noteToDelete = track->begin()->second; // assert(noteToDelete); auto noteToDelete = track->getFirstNote(); toRem.push_back(noteToDelete); CommandPtr cmd = std::make_shared(ms, selection, context, 0, toRem, toAdd); ur->execute(cmd); assertEQ(ms->getTrack(0)->size(), (origSize - 1)); // we removed an event assert(ur->canUndo()); ur->undo(); assert(ms->getTrack(0)->size() == origSize); // we added an event assert(!ur->canUndo()); } static void testTrans() { MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::eightQNotes, 0); MidiSequencerPtr seq = std::make_shared(ms); seq->makeEditor(); seq->assertValid(); // MidiEventPtr firstEvent = seq->context->getTrack()->begin()->second; MidiEventPtr firstEvent = seq->context->getTrack()->getFirstNote(); assert(firstEvent); seq->selection->select(firstEvent); auto cmd = ReplaceDataCommand::makeChangePitchCommand(seq, 1); cmd->execute(); firstEvent = seq->context->getTrack()->begin()->second; float pitch = safe_cast(firstEvent)->pitchCV; assertClose(pitch, -.91666, .01); seq->assertValid(); cmd->undo(); seq->assertValid(); cmd->execute(); seq->assertValid(); } static void testInsert() { MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::empty, 0); MidiLocker l(ms->lock); MidiSequencerPtr seq = std::make_shared(ms); seq->makeEditor(); seq->assertValid(); assertEQ(seq->context->getTrack()->size(), 1); // just an end event MidiNoteEventPtr note = std::make_shared(); note->startTime = 100; note->pitchCV = 1.1f; note->duration = 2; auto cmd = ReplaceDataCommand::makeInsertNoteCommand(seq, note); cmd->execute(); seq->assertValid(); assertEQ(seq->context->getTrack()->size(), 2); auto ev = seq->context->getTrack()->begin()->second; MidiNoteEventPtrC note2 = safe_cast(ev); assert(note2); assert(*note2 == *note); ev = (++seq->context->getTrack()->begin())->second; MidiEndEventPtr end = safe_cast(ev); assert(end); // quantize to even bars int x = (100 + 2) / 4; x *= 4; assert(x < 102); x += 8; // and round up two bars assertEQ(end->startTime, x); // assert(false); // undo and redo printf("add tests for insert note undo/redo\n"); } static void testStartTime() { // make empty song MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::empty, 0); MidiLocker l(ms->lock); MidiSequencerPtr seq = std::make_shared(ms); seq->makeEditor(); seq->assertValid(); // put a note into it at time 100; auto track = seq->context->getTrack(); MidiNoteEventPtr note = std::make_shared(); note->startTime = 100; note->pitchCV = 1.1f; note->duration = 2; auto cmd = ReplaceDataCommand::makeInsertNoteCommand(seq, note); cmd->execute(); seq->assertValid(); assertEQ(seq->selection->size(), 1); // shift note later to 1100 cmd = ReplaceDataCommand::makeChangeStartTimeCommand(seq, 1000.f); seq->undo->execute(cmd); seq->assertValid(); note = track->getFirstNote(); assertEQ(note->startTime, 1100.f); seq->undo->undo(); seq->assertValid(); note = track->getFirstNote(); assertEQ(note->startTime, 100.f); seq->undo->redo(); seq->assertValid(); note = track->getFirstNote(); assertEQ(note->startTime, 1100.f); } static void testDuration() { MidiSongPtr ms = MidiSong::makeTest(MidiTrack::TestContent::empty, 0); MidiLocker l(ms->lock); MidiSequencerPtr seq = std::make_shared(ms); seq->makeEditor(); seq->assertValid(); // put a note into it at time 10, dur 5; auto track = seq->context->getTrack(); MidiNoteEventPtr note = std::make_shared(); note->startTime = 10; note->pitchCV = 1.1f; note->duration = 5; auto cmd = ReplaceDataCommand::makeInsertNoteCommand(seq, note); cmd->execute(); seq->assertValid(); // now increase dur by 1 cmd = ReplaceDataCommand::makeChangeDurationCommand(seq, 1.f); seq->undo->execute(cmd); seq->assertValid(); note = track->getFirstNote(); assert(note); assertEQ(note->startTime, 10.f); assertEQ(note->duration, 6.f) seq->undo->undo(); seq->assertValid(); note = track->getFirstNote(); assertEQ(note->duration, 5.f); seq->undo->redo(); seq->assertValid(); note = track->getFirstNote(); assertEQ(note->duration, 6.f); } void testReplaceCommand() { test0(); test1(); test2(); testTrans(); testInsert(); testStartTime(); testDuration(); }