Phase 27: strengthen undo transactions and improve editor workflow
This commit is contained in:
parent
901a536f10
commit
c4daef7c42
21 changed files with 460 additions and 27 deletions
|
|
@ -27,7 +27,7 @@ namespace {
|
|||
xtc_backend handle;
|
||||
xtc_result seek_result = XTC_OK;
|
||||
xtc_result open_result = XTC_OK, start_result = XTC_OK, stop_result = XTC_OK, close_result = XTC_OK;
|
||||
xtc_result status_result = XTC_OK, submit_result = XTC_OK;
|
||||
xtc_result status_result = XTC_OK, submit_result = XTC_OK, reserve_result = XTC_OK;
|
||||
unsigned int submissions = 0U;
|
||||
xtc_backend_status engine_status = {};
|
||||
bool partial_open = false;
|
||||
|
|
@ -94,7 +94,7 @@ void reset()
|
|||
{
|
||||
CHECK(alive == 0U);
|
||||
open_result = start_result = stop_result = close_result = status_result = XTC_OK;
|
||||
submit_result = seek_result = XTC_OK;
|
||||
submit_result = seek_result = reserve_result = XTC_OK;
|
||||
engine_status = {};
|
||||
engine_status.sample_rate = 48000U;
|
||||
engine_status.buffer_frames = 1024U;
|
||||
|
|
@ -102,6 +102,11 @@ void reset()
|
|||
}
|
||||
}
|
||||
extern "C" {
|
||||
xtc_result __real_xtc_history_reserve(xtc_history *history);
|
||||
xtc_result __wrap_xtc_history_reserve(xtc_history *history) {
|
||||
return reserve_result == XTC_OK ? __real_xtc_history_reserve(history) : reserve_result;
|
||||
}
|
||||
|
||||
xtc_result xtc_backend_open(const xtc_backend_config *config, xtc_backend **out)
|
||||
{
|
||||
CHECK(config->kind == XTC_BACKEND_JACK && config->channel_count == 2U);
|
||||
|
|
@ -334,6 +339,8 @@ int main(int argc, char **argv)
|
|||
CHECK(sequence->position() == 1920); // Graph edits preserve the transport.
|
||||
engine_status.sample_position = 0;
|
||||
std::string take = std::string(directory) + "/take.wav";
|
||||
size_t before_take_nodes = 0, before_take_edges = 0;
|
||||
CHECK(xtc_graph_get_counts(canvas->graph(),&before_take_nodes,&before_take_edges) == XTC_OK);
|
||||
CHECK(window.record_audio(take.c_str()) == XTC_OK && handle.recorder != nullptr);
|
||||
CHECK(canvas->add_node(XTC_NODE_GAIN) == XTC_ERR_INVALID_STATE);
|
||||
CHECK(window.save_project(filename.c_str()) == XTC_ERR_INVALID_STATE);
|
||||
|
|
@ -349,6 +356,14 @@ int main(int argc, char **argv)
|
|||
press(stop);
|
||||
CHECK(handle.recorder == nullptr);
|
||||
CHECK(xtc_project_get_counts(sequence->project(), &track_count, &clip_count) == XTC_OK && clip_count == 2);
|
||||
CHECK(window.undo(false) == XTC_OK);
|
||||
CHECK(xtc_project_get_counts(sequence->project(),&track_count,&clip_count) == XTC_OK && clip_count == 1);
|
||||
CHECK(access(take.c_str(),F_OK) == 0); // Undo never deletes the external take.
|
||||
CHECK(window.undo(false) == XTC_OK);
|
||||
size_t after_take_nodes = 0, after_take_edges = 0;
|
||||
CHECK(xtc_graph_get_counts(canvas->graph(),&after_take_nodes,&after_take_edges) == XTC_OK && after_take_nodes+1 == before_take_nodes);
|
||||
CHECK(window.undo(true) == XTC_OK && window.undo(true) == XTC_OK);
|
||||
CHECK(xtc_project_get_counts(sequence->project(),&track_count,&clip_count) == XTC_OK && clip_count == 2);
|
||||
CHECK(sequence->waveform_count() == 1);
|
||||
// Short clips use their four-pixel draw width for hit testing too.
|
||||
xtc_clip_info audio_clip{};
|
||||
|
|
@ -656,6 +671,36 @@ int main(int argc, char **argv)
|
|||
CHECK(xtc_project_get_automation(sequence->project(),0,&point) == XTC_OK && point.step == 1);
|
||||
unlink("/tmp/xtc-gui-controls-test.xtc"); window.do_callback();
|
||||
}
|
||||
{
|
||||
reset(); MainWindow window(false);
|
||||
auto *sequence = timeline(&window); auto *canvas = graph_canvas(&window);
|
||||
CHECK(sequence->add_track() == XTC_OK && sequence->add_midi_clip() == XTC_OK);
|
||||
const uint64_t track = sequence->selected_track(), clip = sequence->selected_clip();
|
||||
CHECK(window.open_piano_roll() == XTC_OK);
|
||||
CHECK(window.piano_roll()->add_note(0,240,60) == XTC_OK);
|
||||
const uint64_t note = window.piano_roll()->selected_note();
|
||||
CHECK(window.piano_roll()->add_note(240,240,64) == XTC_OK);
|
||||
CHECK(window.piano_roll()->select_note(note));
|
||||
CHECK(window.undo(false) == XTC_OK);
|
||||
CHECK(sequence->selected_track() == track && sequence->selected_clip() == clip);
|
||||
CHECK(window.piano_roll()->clip() == clip && window.piano_roll()->selected_note() == note);
|
||||
const xtc_project *before = sequence->project(); unsigned int bindings[3] = {1,74,11};
|
||||
unsigned int old_submissions = submissions;
|
||||
reserve_result = XTC_ERR_OUT_OF_MEMORY;
|
||||
CHECK(canvas->add_node(XTC_NODE_GAIN) == XTC_ERR_OUT_OF_MEMORY && sequence->project() == before);
|
||||
CHECK(window.set_control_map(0,bindings) == XTC_ERR_OUT_OF_MEMORY && sequence->project() == before);
|
||||
CHECK(window.import_audio("/absent/not-loaded.wav") == XTC_ERR_OUT_OF_MEMORY && sequence->project() == before);
|
||||
CHECK(submissions == old_submissions);
|
||||
reserve_result = XTC_OK;
|
||||
CHECK(window.undo(true) == XTC_OK); // Failed commands preserved redo.
|
||||
size_t count = 0;
|
||||
CHECK(xtc_project_note_count(sequence->project(),&count) == XTC_OK && count == 2);
|
||||
CHECK(canvas->add_node(XTC_NODE_GAIN) == XTC_OK);
|
||||
const size_t node = canvas->selected_node(); int left, top;
|
||||
CHECK(canvas->node_position(node,left,top) && canvas->select_at(left+50,top+30) && canvas->selected_node() == node);
|
||||
CHECK(!canvas->select_at(-20,-20) && canvas->selected_node() == SIZE_MAX);
|
||||
window.do_callback();
|
||||
}
|
||||
if (const char *module = std::getenv("XTC_TEST_PLUGIN")) {
|
||||
reset();
|
||||
MainWindow window(false);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
* reject host allocation/reclamation inside processing. No production hooks. */
|
||||
#include "xtc/xtc_realtime.h"
|
||||
#include "xtc/xtc_native.h"
|
||||
#include "xtc/xtc_control.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -83,9 +84,53 @@ static void graph_limits(void)
|
|||
xtc_plan_destroy(plan);
|
||||
}
|
||||
|
||||
static void history_reservations(void)
|
||||
{
|
||||
xtc_project *project = NULL, *snapshot = NULL;
|
||||
xtc_history *history = NULL;
|
||||
uint64_t track, bus;
|
||||
unsigned int map[3] = {1,74,11}, actual[3];
|
||||
size_t undo_count, redo_count, tracks, clips;
|
||||
int failure, succeeded = 0;
|
||||
assert(xtc_project_create(&project) == XTC_OK);
|
||||
assert(xtc_project_add_track(project,"History",&track) == XTC_OK);
|
||||
assert(xtc_history_create(project,&history) == XTC_OK);
|
||||
assert(xtc_project_set_mix(project,track,.5f,0,0,0) == XTC_OK);
|
||||
assert(xtc_history_record(history,project) == XTC_OK);
|
||||
assert(xtc_history_checkout(history,0,&snapshot) == XTC_OK && xtc_history_accept(history,0) == XTC_OK);
|
||||
xtc_project_destroy(project); project = snapshot; snapshot = NULL;
|
||||
for (failure = 0; failure < 12; ++failure) {
|
||||
xtc_result r;
|
||||
fail_after = failure;
|
||||
r = xtc_history_reserve(history);
|
||||
fail_after = -1;
|
||||
assert(xtc_history_counts(history,&undo_count,&redo_count) == XTC_OK && undo_count == 0 && redo_count == 1);
|
||||
if (r == XTC_OK) { succeeded = 1; break; }
|
||||
assert(r == XTC_ERR_OUT_OF_MEMORY);
|
||||
}
|
||||
assert(succeeded);
|
||||
fail_after = 0; // Fail every allocation: reserved record must still succeed.
|
||||
assert(xtc_history_reserve(history) == XTC_OK);
|
||||
assert(xtc_project_add_bus(project,"Bus",&bus) == XTC_OK);
|
||||
assert(xtc_project_route_track(project,track,bus) == XTC_OK);
|
||||
assert(xtc_project_set_control_map(project,0,map) == XTC_OK);
|
||||
assert(xtc_history_record(history,project) == XTC_OK);
|
||||
fail_after = -1;
|
||||
assert(xtc_history_counts(history,&undo_count,&redo_count) == XTC_OK && undo_count == 1 && redo_count == 0);
|
||||
assert(xtc_history_checkout(history,0,&snapshot) == XTC_OK);
|
||||
assert(xtc_project_get_counts(snapshot,&tracks,&clips) == XTC_OK && tracks == 1 && clips == 0);
|
||||
assert(xtc_project_get_control_map(snapshot,0,actual) == XTC_OK && actual[0] == 7);
|
||||
xtc_project_destroy(snapshot); snapshot = NULL;
|
||||
assert(xtc_history_accept(history,0) == XTC_OK && xtc_history_checkout(history,1,&snapshot) == XTC_OK);
|
||||
assert(xtc_project_get_counts(snapshot,&tracks,&clips) == XTC_OK && tracks == 2);
|
||||
assert(xtc_project_get_control_map(snapshot,0,actual) == XTC_OK && actual[0] == 1 && actual[1] == 74);
|
||||
xtc_project_destroy(snapshot); xtc_project_destroy(project); xtc_history_destroy(history);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
graph_limits();
|
||||
history_reservations();
|
||||
xtc_native_descriptor descriptor = {XTC_NATIVE_ABI_VERSION, sizeof(descriptor),
|
||||
"reliability.gain", XTC_NATIVE_EFFECT, prepare, reset, process, destroy};
|
||||
xtc_graph *graph = NULL;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue