13 ProjectImplP project = ProjectImpl::create (
"TestProject");
15 TASSERT (project->name() ==
"TestProject");
17 const double initial_bpm = project->bpm();
18 TASSERT (initial_bpm >= 10.0 && initial_bpm <= 999.0);
20 auto bpm_connection = project->on_event (
"notify:bpm", [&bpm_notifications] (
const Event &event) { bpm_notifications++; });
23 auto name_connection = project->on_event (
"notify:name", [&name_notifications] (
const Event &event) { name_notifications++; });
27 TASSERT (std::abs (project->bpm() - 130.0) < 0.001);
28 uint64_t last_bpm_notifications = bpm_notifications;
30 TASSERT (std::abs (project->bpm() - 123.5) < 0.001);
31 TASSERT (bpm_notifications > last_bpm_notifications);
36 last_bpm_notifications = bpm_notifications;
40 TASSERT (std::abs (project->bpm() - initial_bpm) < 0.001);
41 TASSERT (bpm_notifications > last_bpm_notifications);
43 last_bpm_notifications = bpm_notifications;
47 TASSERT (std::abs (project->bpm() - 123.5) < 0.001);
48 TASSERT (bpm_notifications > last_bpm_notifications);
53 TASSERT (std::abs (project->bpm() - initial_bpm) < 0.001);
56 const String initial_name = project->name();
57 TASSERT (initial_name ==
"TestProject");
58 uint64_t last_name_notifications = name_notifications;
59 project->name (
"NewName");
60 TASSERT (project->name() ==
"NewName");
61 TASSERT (name_notifications > last_name_notifications);
64 last_name_notifications = name_notifications;
66 TASSERT (project->name() == initial_name);
68 TASSERT (name_notifications > last_name_notifications);
70 last_name_notifications = name_notifications;
72 TASSERT (project->name() ==
"NewName");
73 TASSERT (name_notifications > last_name_notifications);
78 ProjectImplP project2 = ProjectImpl::create (
"TestProject2");
79 project2->name (
"foo");
80 TASSERT (project2->name() ==
"foo");
81 project2->name (
"bar");
82 TASSERT (project2->name() ==
"bar");
90 ProjectP project = ProjectImpl::create (
"TempoTest");
91 TASSERT (project->bpm() == 120.0);
92 TASSERT (project->numerator() == 4);
93 TASSERT (project->denominator() == 4);
96 TASSERT (project->bpm() == 20.0);
97 project->bpm (2000.0);
98 TASSERT (project->bpm() == 300.0);
100 for (
bool numerator : {
true,
false })
102 const auto get = [&] {
return numerator ? project->numerator() : project->denominator(); };
103 const auto set = [&] (
int value) {
105 project->numerator (value);
107 project->denominator (value);
109 uint notifications = 0;
110 auto connection = project->on_event (numerator ?
"notify:numerator" :
"notify:denominator",
111 [&] (const
Event&) { notifications++; });
112 const int initial = get(), value = numerator ? 7 : 8;
113 project->ungroup_undo();
140 ProjectP project = ProjectImpl::create (
"LengthTest");
141 TrackP track = project->create_track();
142 TCMP (project->length(), ==, 0);
143 uint notifications = 0;
144 auto connection = project->on_event (
"notify:length", [&] (
const Event&) { notifications++; });
145 auto expect_length = [&] (
double expected) {
146 TCMP (project->length(), ==, expected);
150 auto check_change = [&] (
auto change,
double expected) {
151 const double before = project->length();
152 project->ungroup_undo();
154 expect_length (expected);
156 expect_length (before);
158 expect_length (expected);
161 project->ungroup_undo();
162 ClipP midi = track->create_midi_clip (
"LengthClip", 1, 3);
164 check_change ([&] { project->bpm (60); }, 8);
165 check_change ([&] { midi->position ({ { 2, 12 }, 0 }); }, 12);
166 check_change ([&] { midi->remove_self(); }, 0);
167 check_change ([&] { track->create_audio_clip (
"LastClip", 20, 4); }, 24);
168 check_change ([&] { track->remove_self(); }, 0);
175project_track_management()
177 ProjectImplP project = ProjectImpl::create (
"TrackTest");
180 TrackS tracks = project->all_tracks();
181 const size_t initial_count = tracks.size();
184 TrackP new_track = project->create_track();
187 tracks = project->all_tracks();
188 TASSERT (tracks.size() == initial_count + 1);
191 auto track_connection = project->on_event (
"notify:all_tracks", [&track_notifications] (
const Event &event) { track_notifications++; });
192 new_track->remove_self();
193 TASSERT (project->all_tracks().size() == initial_count);
194 TASSERT (track_notifications > 0);
201track_outlives_project()
205 for (
size_t i = 0; i < 40; i++)
207 auto project = ProjectImpl::create (
"TrackLifetimeTest");
208 tracks.push_back (project->create_track());
212 for (
const auto &track : tracks)
218project_playback_state()
220 ProjectImplP project = ProjectImpl::create (
"PlaybackTest");
224 TASSERT (!project->is_playing());
233 ProjectImplP project = ProjectImpl::create (
"TrackMuteSoloTest");
236 TrackP track = project->create_track();
245 auto muted_connection = track->on_event (
"notify:muted", [&muted_notifications] (
const Event &event) { muted_notifications++; });
248 auto solo_connection = track->on_event (
"notify:solo", [&solo_notifications] (
const Event &event) { solo_notifications++; });
251 uint64_t last_muted_notifications = muted_notifications;
254 TASSERT (muted_notifications > last_muted_notifications);
257 last_muted_notifications = muted_notifications;
258 track->muted (
false);
260 TASSERT (muted_notifications > last_muted_notifications);
263 uint64_t last_solo_notifications = solo_notifications;
266 TASSERT (solo_notifications > last_solo_notifications);
269 last_solo_notifications = solo_notifications;
272 TASSERT (solo_notifications > last_solo_notifications);
279track_control_classification()
281 ProjectImplP project = ProjectImpl::create (
"ControlTrackTest");
285 TrackS tracks = project->all_tracks();
286 bool have_master =
false, have_control =
false, have_editable =
false;
287 for (
auto &t : tracks)
289 have_master |= t->is_master();
290 have_control |= t->is_control_track();
291 have_editable |= !t->is_control_track();
298 TrackP new_track = project->create_track();
300 TASSERT (!new_track->is_control_track());
301 TASSERT (!new_track->is_master());
305TEST_ADD (track_control_classification);
310 ProjectImplP project = ProjectImpl::create (
"TrackHiddenTest");
313 TrackP track = project->create_track();
321 auto hidden_connection = track->on_event (
"notify:hidden", [&hidden_notifications] (
const Event &event) { hidden_notifications++; });
324 uint64_t last_hidden_notifications = hidden_notifications;
325 project->ungroup_undo();
326 track->hidden (
true);
328 TASSERT (hidden_notifications > last_hidden_notifications);
331 last_hidden_notifications = hidden_notifications;
334 TASSERT (hidden_notifications > last_hidden_notifications);
337 last_hidden_notifications = hidden_notifications;
340 TASSERT (hidden_notifications > last_hidden_notifications);
347check_track_parameter_values (
bool master)
349 struct ParameterTest {
360 for (
size_t property = 0;
property < parameters.size();
property++) {
361 ProjectP project = ProjectImpl::create (
"TrackParameterTest");
363 TrackP track = master ? project->master_track() : project->create_track();
364 TrackP other_track = master ? project->create_track() : project->master_track();
368 auto read_values = [¶meters] (
const TrackP &t) {
370 for (
size_t i = 0; i < parameters.size(); i++)
371 values[i] = (t.get()->*parameters[i].get)();
374 const Values other_values = read_values (other_track);
376 Values notified_values = {};
378 for (
size_t i = 0; i < parameters.size(); i++)
379 connections[i] = track->on_event (
String (
"notify:") + parameters[i].name, [&, i] (
const Event&) {
381 notified_values[i] = (track.get()->*parameters[i].get)();
383 auto verify = [&] (
const Values &expected,
const Values &before,
const auto &previous_notifications) {
384 const Values actual = read_values (track);
385 for (
size_t i = 0; i < parameters.size(); i++) {
386 TASSERT (std::abs (actual[i] - expected[i]) < 0.001f);
387 if (expected[i] != before[i]) {
388 TASSERT (notifications[i] > previous_notifications[i]);
389 TASSERT (std::abs (notified_values[i] - expected[i]) < 0.001f);
392 TASSERT (read_values (other_track) == other_values);
394 const auto ¶meter = parameters[property];
395 const Values initial = read_values (track);
396 auto previous_notifications = notifications;
397 project->group_undo (parameter.name);
398 (track.get()->*parameter.set) (parameter.value);
399 project->ungroup_undo();
400 const Values changed = read_values (track);
401 TASSERT (std::abs (changed[property] - parameter.value) < 0.001f);
402 TASSERT (changed[property] != initial[property]);
404 TASSERT (changed[0] != initial[0]);
405 TASSERT (changed[1] != initial[1]);
407 verify (changed, initial, previous_notifications);
409 TASSERT (!project->can_redo());
411 for (
int repeat = 0; repeat < 2; repeat++) {
412 previous_notifications = notifications;
414 verify (initial, changed, previous_notifications);
417 previous_notifications = notifications;
419 verify (changed, initial, previous_notifications);
420 TASSERT (!project->can_redo());
428track_parameter_values()
430 check_track_parameter_values (
false);
435master_parameter_values()
437 check_track_parameter_values (
true);
444 ProjectImplP project = ProjectImpl::create (
"TrackVolumePanTest");
447 TrackP track = project->create_track();
451 double initial_vol = track->volume_db();
452 TASSERT (initial_vol >= -100.0 && initial_vol <= 20.0);
456 auto volume_connection = track->on_event (
"notify:volume_db", [&volume_notifications] (
const Event &event) { volume_notifications++; });
459 auto pan_connection = track->on_event (
"notify:pan", [&pan_notifications] (
const Event &event) { pan_notifications++; });
462 uint64_t last_volume_notifications = volume_notifications;
463 track->volume_db (-6.0);
464 TASSERT (std::abs (track->volume_db() - (-6.0)) < 0.01);
465 TASSERT (volume_notifications > last_volume_notifications);
468 last_volume_notifications = volume_notifications;
469 track->volume_db (0.0);
470 TASSERT (std::abs (track->volume_db()) < 0.01);
471 TASSERT (volume_notifications > last_volume_notifications);
474 double initial_pan = track->pan();
475 TASSERT (initial_pan >= -1.0 && initial_pan <= 1.0);
478 uint64_t last_pan_notifications = pan_notifications;
480 TASSERT (std::abs (track->pan() - 0.5) < 0.01);
481 TASSERT (pan_notifications > last_pan_notifications);
484 last_pan_notifications = pan_notifications;
486 TASSERT (std::abs (track->pan() - (-0.5)) < 0.01);
487 TASSERT (pan_notifications > last_pan_notifications);
496 ProjectImplP project = ProjectImpl::create (
"TrackNameTest");
499 TrackP first = project->all_tracks().back();
500 TASSERT (first->name() ==
"Track 1" && project->master_track()->name() ==
"Master");
501 TrackP track = project->create_track();
502 TASSERT (track && track->name() ==
"Track 2");
505 track->name (
"MyTrack");
506 TASSERT (track->name() ==
"MyTrack");
508 track->name (
"AnotherName");
509 TASSERT (track->name() ==
"AnotherName");
513 TASSERT (track->name() ==
"Track 1");
514 track->name (
"Track 2");
517 first->remove_self();
518 TASSERT (track->name() ==
"Track 2");
519 project->ungroup_undo();
520 const size_t ntracks = project->all_tracks().size();
521 TrackP third = project->create_track();
522 TASSERT (third->name() ==
"Track 3");
524 TASSERT (project->all_tracks().size() == ntracks);
534 TrackS tracks = project->all_tracks();
535 tracks.push_back (project->master_track());
536 for (
const TrackP &track : tracks)
537 if (track->is_control_track() || track->is_master())
539 const String initial = track->name();
540 if (initial ==
"Chord")
542 const StringS read_only = track->read_only_properties();
544 uint notifications = 0;
545 auto connection = track->on_event (
"notify:name", [&] (
const Event&) { notifications++; });
546 track->name (
"Ignored Name");
547 TASSERT (track->name() == initial && notifications == 0);
557 TrackP track = project->create_track();
558 for (
const String &type : {
"text",
"insert" })
560 PluginP plugin = track->create_plugin (type);
562 const String initial = plugin->name();
563 const StringS read_only = plugin->read_only_properties();
565 uint notifications = 0;
566 auto connection = plugin->on_event (
"notify:name", [&] (
const Event&) { notifications++; });
567 const String project_name = project->name();
568 project->ungroup_undo();
569 project->name (project_name +
" marker");
571 TASSERT (plugin->name() == initial && notifications == 0);
573 TASSERT (project->name() == project_name);
575 TASSERT (project->name() == project_name +
" marker");
576 plugin->name (
"New Name");
577 TASSERT (plugin->name() ==
"New Name" && notifications > 0);
580 TASSERT (plugin->name() == initial && notifications > 0);
582 PluginP
fixed = track->create_plugin (
"4osc");
585 const StringS read_only =
fixed->read_only_properties();
587 fixed->name (
"Ignored Name");
594project_name_notifications()
597 TrackP track = project->create_track();
600 track->create_midi_clip (
"Midi", 0, 1),
601 track->create_audio_clip (
"Audio", 2, 1),
602 track->create_plugin (
"text"),
603 track->create_plugin (
"insert"),
605 uint notifications = 0;
606 auto connection = project->on_event (
"notify:name", [&] (
const Event&) { notifications++; });
607 for (
const auto &child : children)
610 project->ungroup_undo();
611 child->name (
"Child Name");
612 TASSERT (project->name() ==
"ProjectNameNotifyTest" && notifications == 0);
618 project->name (
"Project Name");
622TEST_ADD (project_name_notifications);
628 TrackP track = project->create_track();
630 for (
const TrackP &control : project->all_tracks())
631 if (control->is_control_track() && control->name() ==
"Chord")
634 const StringS read_only = chord->read_only_properties();
638 { track,
"Track 1" },
640 { track->create_midi_clip (
"Midi", 0, 1),
"" },
641 { track->create_audio_clip (
"Audio", 2, 1),
"" },
642 { track->create_plugin (
"text"),
"Text Plugin" },
643 { track->create_plugin (
"insert"),
"Insert Plugin" },
645 for (
const auto &[gadget, default_name] : writable)
648 const String initial = gadget->name();
649 uint notifications = 0;
650 auto connection = gadget->on_event (
"notify:name", [&] (
const Event&) { notifications++; });
652 TASSERT (gadget->name() == expected && notifications > 0);
655 gadget->name (
"First Name");
656 check (
"First Name");
657 gadget->name (
"Second Name");
658 check (
"Second Name");
659 gadget->name (
"Second Name");
662 check (
"First Name");
666 check (
"First Name");
668 check (
"Second Name");
670 check (default_name);
672 check (
"Second Name");
674 check (default_name);
685 uint notifications = 0;
686 auto connection = server.on_event (
"notify:name", [&] (
const Event&) { notifications++; });
687 for (
const String &name : {
"Renamed Server",
"" })
698 ProjectImplP project = ProjectImpl::create (
"ClipTest");
701 TrackP track = project->create_track();
707 ClipP clip = trackimpl->create_midi_clip (
"TestClip", 0.0, 4.0);
708 TASSERT (clip && clip->name() ==
"TestClip");
709 TASSERT (track->create_audio_clip (
"TestAudio", 4.0, 4.0)->name() ==
"TestAudio");
716clip_audio_notes_read_only()
718 ProjectImplP project = ProjectImpl::create (
"AudioNotesReadOnly");
719 ClipP clip = project->create_track()->create_audio_clip (
"Audio", 0, 4);
720 const StringS read_only = clip->read_only_properties();
722 uint notifications = 0;
723 auto connection = clip->on_event (
"notify", [&] (
const Event&) { notifications++; });
724 project->clear_undo();
726 clip->all_notes ({ note });
727 TASSERT (clip->all_notes().empty());
728 TASSERT (!project->can_undo() && notifications == 0);
731TEST_ADD (clip_audio_notes_read_only);
736 ProjectP project = ProjectImpl::create (
"ClipNotesTest");
737 TrackP track = project->create_track();
738 project->denominator (8);
739 ClipP clip = track->create_midi_clip (
"NotesClip", 0.0, 4.0);
740 TASSERT (clip->all_notes().empty());
753 ClipNoteS added = clip->change_batch ({ first, second },
"Add Notes");
755 TASSERT (added[0].
id > 0 && added[1].
id > 0 && added[0].
id != added[1].
id);
756 first.id = added[0].id;
757 second.id = added[1].id;
758 TASSERT (added[0] == first && added[1] == second);
759 TASSERT (clip->list_all_notes() == added);
761 TASSERT (clip->all_notes().empty());
763 TASSERT (clip->all_notes() == added);
772 TASSERT (clip->change_batch ({ moved },
"Move Note") == ClipNoteS { moved });
773 TASSERT ((clip->all_notes() == ClipNoteS { first, moved }));
775 TASSERT (clip->all_notes() == added);
777 TASSERT ((clip->all_notes() == ClipNoteS { first, moved }));
781 clip->change_batch ({ removed },
"Delete Note");
782 TASSERT (clip->all_notes() == ClipNoteS { moved });
784 TASSERT ((clip->all_notes() == ClipNoteS { first, moved }));
786 TASSERT (clip->all_notes() == ClipNoteS { moved });
788 clip->all_notes ({ second });
789 const auto replaced = clip->all_notes();
790 TASSERT (replaced.size() == 1 && replaced[0].id != second.id);
791 second.id = replaced[0].id;
792 TASSERT (replaced == ClipNoteS { second });
794 TASSERT (clip->all_notes() == ClipNoteS { moved });
796 TASSERT (clip->all_notes() == replaced);
800 const auto mixed = clip->change_batch ({ first, fresh },
"Skip Deleted Handle");
801 TASSERT (mixed.size() == 2 && mixed[0].id == 0 && mixed[1].id > 0);
802 TASSERT (clip->all_notes().size() == 2);
803 const auto before_batch = clip->all_notes();
804 ClipNote modified = before_batch[0], deleted = before_batch[0];
806 deleted.length_beats = 0;
807 const auto ordered = clip->change_batch ({ modified, fresh, deleted },
"Delete Before Modify");
808 TASSERT (ordered.size() == 3 && ordered[0].id == 0 && ordered[1].id > 0 && ordered[2].id == deleted.id);
809 TASSERT ((clip->all_notes() == ClipNoteS { before_batch[1], ordered[1] }));
811 TASSERT (clip->all_notes() == before_batch);
813 TASSERT ((clip->all_notes() == ClipNoteS { before_batch[1], ordered[1] }));
815 TASSERT (clip->change_batch ({ fresh },
"Edit Removed Clip").empty());
822clip_note_notifications()
824 ProjectImplP project = ProjectImpl::create (
"NoteNotifications");
825 ClipP clip = project->create_track()->create_midi_clip (
"Notes", 0, 4);
827 auto connection = clip->on_event (
"notify", [&] (
const Event &event) {
828 if (event.detail() ==
"notes" || event.detail() ==
"all_notes")
829 notified[event.detail()] = clip->all_notes();
831 auto require_notifies = [&] (
const ClipNoteS ¬es) {
832 TASSERT (notified.count (
"notes") && notified.at (
"notes") == notes);
833 TASSERT (notified.count (
"all_notes") && notified.at (
"all_notes") == notes);
836 for (
int step = 0; step < 3; step++)
838 const ClipNoteS before = clip->all_notes();
839 project->clear_undo();
843 note = before.at (0);
847 note.length_beats = 0;
849 clip->change_batch ({ note },
"Change Note");
850 const ClipNoteS after = clip->all_notes();
852 require_notifies (after);
854 TASSERT (clip->all_notes() == before);
855 require_notifies (before);
857 TASSERT (clip->all_notes() == after);
858 require_notifies (after);
867 ProjectP project = ProjectImpl::create (
"ClipRangeTest");
868 TrackP track = project->create_track();
870 project->numerator (6);
871 for (
int denominator : { 4, 8, 16 })
873 project->denominator (denominator);
874 for (ClipP clip : { track->create_midi_clip (
"MidiRange", 0.5, 1.25),
875 track->create_audio_clip (
"AudioRange", 0.5, 1.25) })
878 const double beats_per_second = denominator / 2.0;
879 TASSERT (clip->position() == initial);
880 TASSERT (clip->start_beat() == initial.time.start * beats_per_second);
881 TASSERT (clip->end_beat() == initial.time.
end * beats_per_second);
882 uint position_notifications = 0, start_notifications = 0, end_notifications = 0;
883 auto position_connection = clip->on_event (
"notify:position", [&] (
const Event&) { position_notifications++; });
884 auto start_connection = clip->on_event (
"notify:start_beat", [&] (
const Event&) { start_notifications++; });
885 auto end_connection = clip->on_event (
"notify:end_beat", [&] (
const Event&) { end_notifications++; });
886 auto check_position = [&] (
const ClipPosition &expected)
888 TASSERT (clip->position() == expected);
889 TASSERT (clip->start_beat() == expected.time.start * beats_per_second);
890 TASSERT (clip->end_beat() == expected.time.end * beats_per_second);
891 TASSERT (position_notifications > 0 && start_notifications > 0 && end_notifications > 0);
892 position_notifications = start_notifications = end_notifications = 0;
895 clip->position (changed);
896 check_position (changed);
898 check_position (initial);
900 check_position (changed);
901 const ClipPosition offset_changed { changed.time, 0.875 };
902 clip->position (offset_changed);
903 check_position (offset_changed);
905 check_position (changed);
907 check_position (offset_changed);
915clip_mute_volume_pan()
917 ProjectImplP project = ProjectImpl::create (
"ClipMuteVolPanTest");
920 TrackP track = project->create_track();
927 ClipP mclip = trackimpl->create_midi_clip (
"MidiClip", 0.0, 4.0);
935 auto muted_connection = mclip->on_event (
"notify:muted", [&muted_notifications] (
const Event &event) { muted_notifications++; });
938 uint64_t last_muted_notifications = muted_notifications;
941 TASSERT (muted_notifications > last_muted_notifications);
943 last_muted_notifications = muted_notifications;
945 TASSERT (!mclip->muted() && muted_notifications > last_muted_notifications);
946 last_muted_notifications = muted_notifications;
948 TASSERT (mclip->muted() && muted_notifications > last_muted_notifications);
951 last_muted_notifications = muted_notifications;
952 mclip->muted (
false);
954 TASSERT (muted_notifications > last_muted_notifications);
958 auto volume_connection = mclip->on_event (
"notify:volume", [&volume_notifications] (
const Event &event) { volume_notifications++; });
961 uint64_t last_volume_notifications = volume_notifications;
962 mclip->volume (-6.0);
963 TASSERT (std::abs (mclip->volume() - (-6.0)) < 0.01);
964 TASSERT (volume_notifications > last_volume_notifications);
967 last_volume_notifications = volume_notifications;
969 TASSERT (std::abs (mclip->volume()) < 0.01);
970 TASSERT (volume_notifications > last_volume_notifications);
973 ClipP aclip = trackimpl->create_audio_clip (
"AudioClip", 0.0, 4.0);
978 auto pan_connection = aclip->on_event (
"notify:pan", [&pan_notifications] (
const Event &event) { pan_notifications++; });
981 TASSERT (std::abs (aclip->pan()) < 0.01);
984 uint64_t last_pan_notifications = pan_notifications;
986 TASSERT (std::abs (aclip->pan() - 0.5) < 0.01);
987 TASSERT (pan_notifications > last_pan_notifications);
990 last_pan_notifications = pan_notifications;
992 TASSERT (std::abs (aclip->pan() - (-0.5)) < 0.01);
993 TASSERT (pan_notifications > last_pan_notifications);
996 uint64_t audio_volume_notifications = 0;
997 auto audio_volume_connection = aclip->on_event (
"notify:volume", [&audio_volume_notifications] (
const Event &event) { audio_volume_notifications++; });
999 last_volume_notifications = audio_volume_notifications;
1000 aclip->volume (-3.0);
1001 TASSERT (std::abs (aclip->volume() - (-3.0)) < 0.01);
1002 TASSERT (audio_volume_notifications > last_volume_notifications);
1011 ProjectImplP project = ProjectImpl::create (
"ClipUndoRedoTest");
1014 TrackP track = project->create_track();
1021 ClipP mclip = trackimpl->create_midi_clip (
"UndoMidiClip", 0.0, 4.0);
1025 auto muted_connection = mclip->on_event (
"notify:muted", [&muted_notifications] (
const Event &event) { muted_notifications++; });
1028 uint64_t last_muted_notifications = muted_notifications;
1029 mclip->muted (
true);
1031 TASSERT (muted_notifications > last_muted_notifications);
1034 TASSERT (project->can_undo());
1039 TASSERT (project->can_redo());
1045 auto volume_connection = mclip->on_event (
"notify:volume", [&volume_notifications] (
const Event &event) { volume_notifications++; });
1048 double initial_vol = mclip->volume();
1049 uint64_t last_volume_notifications = volume_notifications;
1050 mclip->volume (-12.0);
1051 TASSERT (std::abs (mclip->volume() - (-12.0)) < 0.01);
1052 TASSERT (volume_notifications > last_volume_notifications);
1055 TASSERT (project->can_undo());
1057 TASSERT (std::abs (mclip->volume() - initial_vol) < 0.01);
1060 TASSERT (project->can_redo());
1062 TASSERT (std::abs (mclip->volume() - (-12.0)) < 0.01);
1065 ClipP aclip = trackimpl->create_audio_clip (
"UndoAudioClip", 0.0, 4.0);
1069 auto pan_connection = aclip->on_event (
"notify:pan", [&pan_notifications] (
const Event &event) { pan_notifications++; });
1072 double initial_pan = aclip->pan();
1073 uint64_t last_pan_notifications = pan_notifications;
1075 TASSERT (std::abs (aclip->pan() - 0.8) < 0.01);
1076 TASSERT (pan_notifications > last_pan_notifications);
1079 TASSERT (project->can_undo());
1081 TASSERT (std::abs (aclip->pan() - initial_pan) < 0.01);
1084 TASSERT (project->can_redo());
1086 TASSERT (std::abs (aclip->pan() - 0.8) < 0.01);
1096 batch.push_back (note);
1099 auto notes_connection = mclip->on_event (
"notify:notes", [¬es_notifications] (
const Event &event) { notes_notifications++; });
1102 uint64_t last_notes_notifications = notes_notifications;
1103 mclip->change_batch (batch,
"Add Note");
1104 TASSERT (mclip->list_all_notes().size() == 1);
1105 TASSERT (notes_notifications > last_notes_notifications);
1108 TASSERT (project->can_undo());
1110 TASSERT (mclip->list_all_notes().empty());
1113 TASSERT (project->can_redo());
1115 TASSERT (mclip->list_all_notes().size() == 1);
1118 const ClipPosition initial_position = mclip->position();
1120 changed_position.time.start += 0.375;
1121 changed_position.time.end += 0.375;
1125 auto range_connection = mclip->on_event (
"notify:position", [&range_notifications] (
const Event &event) { range_notifications++; });
1127 uint64_t last_range_notifications = range_notifications;
1128 mclip->position (changed_position);
1129 TASSERT (mclip->position() == changed_position);
1130 TASSERT (range_notifications > last_range_notifications);
1133 TASSERT (project->can_undo());
1135 TASSERT (mclip->position() == initial_position);
1138 TASSERT (project->can_redo());
1140 TASSERT (mclip->position() == changed_position);
1149 ProjectP project = ProjectImpl::create (
"PluginTest");
1150 TrackP track = project->create_track();
1152 PluginS plugins = track->list_plugins();
1154 PluginP plugin = plugins.front();
1156 TASSERT (!plugin->name().empty());
1157 TASSERT (!plugin->plugin_type().empty());
1159 for (
bool check_enabled : {
true,
false })
1161 const auto get = [&] {
return check_enabled ? plugin->enabled() : plugin->frozen(); };
1162 const auto set = [&] (
bool value) {
1164 plugin->enabled (value);
1166 plugin->frozen (value);
1168 uint notifications = 0;
1169 auto connection = plugin->on_event (check_enabled ?
"notify:enabled" :
"notify:frozen",
1170 [&] (const
Event&) { notifications++; });
1171 const bool initial = get();
1172 project->ungroup_undo();
1176 TASSERT (project->can_undo());
1184 TASSERT (project->can_redo());
1192 uint removed_count = 0;
1193 auto removed_connection = plugin->on_event (
"object:removed", [&] (
const Event&) { removed_count++; });
1194 plugin->remove_self();
virtual StringS read_only_properties() const
List x()/x (v) properties that this object can't change, their setters ignore the value or warn.
Central singleton, serves as API entry point.
virtual ProjectP create_project(String projectname)=0
Create a new project (name is modified to be unique if necessary.
static Server & instance()
Retrieve global Server instance.
Container for Clip objects and sequencing information.
virtual float volume_db() const =0
Get track volume in dB.
virtual float pan() const =0
Get track pan (-1.0 to 1.0).
virtual float slider_pos() const =0
Get track volume fader position.
bool check(const String &file, const String &mode)
The Anklang C++ API namespace.
uint32_t uint
Provide 'uint' as convenience type.
A Tracktion MIDI note with a session handle for edits.
bool mute
Tracktion note colour index.
int colour
Velocity, 0 .. 127.
double start_beat
Musical note as MIDI key, 0 .. 127.
int velocity
Duration in Tracktion beats.
int note_number
Session handle, > 0 for existing notes.
double length_beats
Position in Tracktion beats from the start of the clip.
Tracktion clip position in seconds.
Structure for callback based notifications.
#define TASSERT(cond)
Unconditional test assertion, enters breakpoint if not fullfilled.
#define TCMP(a, cmp, b)
Compare a and b according to operator cmp, verbose on failiure.
#define TEST_ADD(fun)
Register a function to run as part of the unit test suite.