Phase 4: Add modular graph editor and transactional graph edits
This commit is contained in:
parent
2ecc03b482
commit
5c41d7f6da
27 changed files with 1023 additions and 64 deletions
|
|
@ -78,7 +78,7 @@ int main(void)
|
|||
xtc_backend_config config = {XTC_BACKEND_JACK, "test", 64U, 1U};
|
||||
xtc_backend *backend = NULL;
|
||||
xtc_backend_status status;
|
||||
xtc_graph *graph = NULL;
|
||||
xtc_graph *graph = NULL, *invalid_graph = NULL;
|
||||
size_t node, i;
|
||||
const char *name;
|
||||
int visits = 0, iteration;
|
||||
|
|
@ -110,7 +110,11 @@ int main(void)
|
|||
CHECK(xtc_graph_add_gain(graph, 0.5f, &node) == XTC_OK);
|
||||
CHECK(xtc_backend_open(&config, &backend) == XTC_OK);
|
||||
CHECK(xtc_backend_submit(backend, graph) == XTC_OK);
|
||||
CHECK(xtc_backend_submit(backend, graph) == XTC_ERR_CAPACITY);
|
||||
CHECK(xtc_backend_submit(backend, graph) == XTC_OK); /* Stopped edits replace pending plan. */
|
||||
CHECK(xtc_graph_create(1U, &invalid_graph) == XTC_OK);
|
||||
CHECK(xtc_graph_add_oscillator(invalid_graph, 25000.0f, &node) == XTC_OK);
|
||||
CHECK(xtc_backend_submit(backend, invalid_graph) == XTC_ERR_INVALID_ARGUMENT);
|
||||
CHECK(xtc_backend_get_status(backend, &status) == XTC_OK && status.submitted_revision == 1U && status.active_revision == 0U);
|
||||
CHECK(xtc_backend_port_name(backend, XTC_PORT_OUTPUT, &name) == XTC_OK && strcmp(name,"test:output") == 0);
|
||||
CHECK(xtc_backend_visit_ports(backend, XTC_PORT_INPUT, visit, &visits) == XTC_OK && visits == 1);
|
||||
CHECK(xtc_backend_connect(backend, XTC_PORT_OUTPUT, "fake:in") == XTC_ERR_INVALID_STATE);
|
||||
|
|
@ -124,6 +128,11 @@ int main(void)
|
|||
CHECK(xtc_backend_disconnect(backend, XTC_PORT_OUTPUT, "fake:in") == XTC_OK);
|
||||
for (i = 0U; i < 128U; ++i) input[i] = 1.0f;
|
||||
CHECK(process_cb(32U, context) == 0 && output[0] == 0.5f);
|
||||
CHECK(xtc_backend_get_status(backend, &status) == XTC_OK && status.active_revision == status.submitted_revision);
|
||||
CHECK(xtc_backend_submit(backend, invalid_graph) == XTC_ERR_INVALID_ARGUMENT);
|
||||
CHECK(xtc_backend_submit(backend, graph) == XTC_OK);
|
||||
CHECK(xtc_backend_submit(backend, graph) == XTC_ERR_CAPACITY);
|
||||
CHECK(process_cb(32U, context) == 0 && output[0] == 0.5f);
|
||||
CHECK(size_cb(128U, context) == 0);
|
||||
CHECK(process_cb(128U, context) == 0 && output[127] == 0.0f);
|
||||
CHECK(xtc_backend_get_status(backend, &status) == XTC_OK && status.process_result == XTC_ERR_CAPACITY);
|
||||
|
|
@ -166,6 +175,7 @@ int main(void)
|
|||
}
|
||||
CHECK(closed >= 104);
|
||||
CHECK(xtc_backend_close(NULL) == XTC_OK);
|
||||
xtc_graph_destroy(invalid_graph);
|
||||
xtc_graph_destroy(graph);
|
||||
puts("JACK backend fault-injection tests passed.");
|
||||
return 0;
|
||||
|
|
|
|||
83
tests/unit/test_graph_edits.c
Normal file
83
tests/unit/test_graph_edits.c
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#include "xtc/xtc_engine.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#define CHECK(c) do { if (!(c)) { fprintf(stderr,"FAIL %s:%d: %s\n",__FILE__,__LINE__,#c); return 1; } } while (0)
|
||||
static xtc_result apply(xtc_graph **graph, xtc_graph_edit *edit, size_t *id)
|
||||
{
|
||||
xtc_graph *candidate = NULL;
|
||||
xtc_result result = xtc_graph_apply_edit(*graph, edit, &candidate, id);
|
||||
if (result == XTC_OK) { xtc_graph_destroy(*graph); *graph = candidate; }
|
||||
return result;
|
||||
}
|
||||
int main(void)
|
||||
{
|
||||
xtc_graph *graph = NULL, *candidate = NULL;
|
||||
xtc_plan *old = NULL, *fresh = NULL;
|
||||
xtc_graph_edit edit = {0};
|
||||
xtc_node_info info;
|
||||
xtc_connection_info connection;
|
||||
size_t osc, gain, meter, output, added = 77U, nodes, edges;
|
||||
float samples[4] = {9,9,9,9}, peak;
|
||||
CHECK(xtc_graph_create(8U, &graph) == XTC_OK);
|
||||
CHECK(xtc_graph_require_output_nodes(graph, 2) == XTC_ERR_INVALID_ARGUMENT);
|
||||
CHECK(xtc_graph_require_output_nodes(graph, 1) == XTC_OK);
|
||||
CHECK(xtc_graph_compile(graph, 48000.0, 4U, &fresh) == XTC_OK);
|
||||
CHECK(xtc_plan_process(fresh, NULL, samples, 4U) == XTC_OK && samples[0] == 0.0f && samples[3] == 0.0f);
|
||||
xtc_plan_destroy(fresh);
|
||||
edit.kind = XTC_EDIT_ADD_NODE; edit.data.add.type = XTC_NODE_OSCILLATOR; edit.data.add.value = 12000.0f;
|
||||
CHECK(apply(&graph, &edit, &osc) == XTC_OK);
|
||||
CHECK(xtc_graph_compile(graph, 48000.0, 4U, &fresh) == XTC_OK);
|
||||
CHECK(xtc_plan_process(fresh, NULL, samples, 4U) == XTC_OK && samples[1] == 0.0f); /* No output. */
|
||||
xtc_plan_destroy(fresh);
|
||||
edit.data.add.type = XTC_NODE_GAIN; edit.data.add.value = 0.25f;
|
||||
CHECK(apply(&graph, &edit, &gain) == XTC_OK);
|
||||
edit.data.add.type = XTC_NODE_METER;
|
||||
CHECK(apply(&graph, &edit, &meter) == XTC_OK);
|
||||
edit.data.add.type = XTC_NODE_OUTPUT;
|
||||
CHECK(apply(&graph, &edit, &output) == XTC_OK);
|
||||
edit.kind = XTC_EDIT_CONNECT;
|
||||
edit.data.connection = (xtc_connection_info){osc, 1U, gain, 0U};
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_OK);
|
||||
edit.data.connection = (xtc_connection_info){gain, 1U, meter, 0U};
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_OK);
|
||||
edit.data.connection = (xtc_connection_info){meter, 1U, output, 0U};
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_OK);
|
||||
CHECK(xtc_graph_get_connection(graph, 2U, &connection) == XTC_OK && connection.source_node == meter && connection.destination_node == output);
|
||||
CHECK(xtc_graph_compile(graph, 48000.0, 4U, &old) == XTC_OK);
|
||||
edit.data.connection = (xtc_connection_info){meter, 1U, gain, 0U};
|
||||
CHECK(xtc_graph_apply_edit(graph, &edit, &candidate, &added) == XTC_ERR_GRAPH_CYCLE && candidate == NULL && added == 77U);
|
||||
CHECK(xtc_graph_get_counts(graph, &nodes, &edges) == XTC_OK && nodes == 4U && edges == 3U);
|
||||
edit.data.connection = (xtc_connection_info){gain, 0U, meter, 0U};
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_ERR_INVALID_ARGUMENT);
|
||||
edit.kind = XTC_EDIT_REMOVE_NODE; edit.data.node_id = gain;
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_OK);
|
||||
CHECK(xtc_graph_get_counts(graph, &nodes, &edges) == XTC_OK && nodes == 3U && edges == 1U);
|
||||
CHECK(xtc_graph_get_node(graph, 1U, &info) == XTC_OK && info.id == meter && info.type == XTC_NODE_METER);
|
||||
CHECK(xtc_graph_get_connection(graph, 0U, &connection) == XTC_OK && connection.source_node == meter);
|
||||
edit.kind = XTC_EDIT_CONNECT; edit.data.connection = (xtc_connection_info){osc, 1U, meter, 0U};
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_OK);
|
||||
CHECK(xtc_graph_compile(graph, 48000.0, 4U, &fresh) == XTC_OK);
|
||||
CHECK(xtc_plan_process(old, NULL, samples, 4U) == XTC_OK && fabsf(samples[1] - 0.25f) < 0.00001f);
|
||||
CHECK(xtc_plan_process(fresh, NULL, samples, 4U) == XTC_OK && fabsf(samples[1] - 1.0f) < 0.00001f);
|
||||
CHECK(xtc_plan_meter_peak(fresh, meter, &peak) == XTC_OK && fabsf(peak - 1.0f) < 0.00001f);
|
||||
xtc_plan_destroy(old); xtc_plan_destroy(fresh);
|
||||
edit.kind = XTC_EDIT_DISCONNECT;
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_OK);
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_ERR_NOT_FOUND);
|
||||
edit.kind = XTC_EDIT_ADD_NODE; edit.data.add.type = XTC_NODE_GAIN; edit.data.add.value = NAN;
|
||||
CHECK(apply(&graph, &edit, &added) == XTC_ERR_INVALID_ARGUMENT && added == 77U);
|
||||
edit.data.add.value = 2.0f;
|
||||
CHECK(apply(&graph, &edit, &added) == XTC_OK && added > output); /* Never reuse gain's ID. */
|
||||
edit.kind = XTC_EDIT_REMOVE_NODE; edit.data.node_id = gain;
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_ERR_NOT_FOUND);
|
||||
edit.kind = (xtc_graph_edit_kind)999;
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_ERR_INVALID_ARGUMENT);
|
||||
edit.kind = XTC_EDIT_ADD_NODE; edit.data.add.type = (xtc_node_type)999;
|
||||
CHECK(apply(&graph, &edit, NULL) == XTC_ERR_INVALID_ARGUMENT);
|
||||
CHECK(xtc_graph_get_node(graph, SIZE_MAX, &info) == XTC_ERR_NOT_FOUND);
|
||||
CHECK(xtc_graph_get_connection(graph, SIZE_MAX, &connection) == XTC_ERR_NOT_FOUND);
|
||||
CHECK(xtc_graph_apply_edit(NULL, &edit, &candidate, NULL) == XTC_ERR_INVALID_ARGUMENT && candidate == NULL);
|
||||
xtc_graph_destroy(graph);
|
||||
puts("Transactional graph edits, stable IDs, snapshots and rendering passed.");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -89,7 +89,9 @@ static int validation(void)
|
|||
CHECK(xtc_graph_create(SIZE_MAX, &graph) == XTC_ERR_INVALID_ARGUMENT && graph == NULL);
|
||||
CHECK(xtc_graph_create(0U, &graph) == XTC_ERR_INVALID_ARGUMENT);
|
||||
CHECK(xtc_graph_create(4U, &graph) == XTC_OK);
|
||||
CHECK(xtc_graph_compile(graph, 48000.0, 4U, &plan) == XTC_ERR_INVALID_STATE && plan == NULL);
|
||||
CHECK(xtc_graph_compile(graph, 48000.0, 4U, &plan) == XTC_OK);
|
||||
xtc_plan_destroy(plan);
|
||||
plan = NULL;
|
||||
CHECK(xtc_graph_add_gain(graph, NAN, &unchanged) == XTC_ERR_INVALID_ARGUMENT && unchanged == 77U);
|
||||
CHECK(xtc_graph_add_oscillator(graph, -1.0f, &unchanged) == XTC_ERR_INVALID_ARGUMENT);
|
||||
CHECK(xtc_graph_add_gain(graph, 1.0f, &a) == XTC_OK);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ static void *worker(void *context)
|
|||
while (!__atomic_load_n(&state->stop, __ATOMIC_ACQUIRE)) {
|
||||
if (xtc_realtime_process(state->engine, input, output, 32U) != XTC_OK)
|
||||
__atomic_store_n(&state->failed, 1U, __ATOMIC_RELAXED);
|
||||
xtc_realtime_status status;
|
||||
(void)xtc_realtime_get_status(state->engine, &status);
|
||||
float expected = status.active_revision == 2U ? 2.0f : status.active_revision % 2U ? 2.0f : 1.0f;
|
||||
if (output[0] != expected) __atomic_store_n(&state->failed, 1U, __ATOMIC_RELAXED);
|
||||
/* A whole block must come from one plan. No partially edited gains. */
|
||||
for (i = 0U; i < 32U; ++i)
|
||||
if ((output[i] != 0.0f && output[i] != 1.0f && output[i] != 2.0f) || output[i] != output[0])
|
||||
|
|
@ -41,10 +45,12 @@ static int run(void)
|
|||
CHECK(xtc_graph_add_gain(two, 2.0f, &node) == XTC_OK);
|
||||
CHECK(xtc_realtime_submit(engine, one) == XTC_OK);
|
||||
CHECK(xtc_realtime_submit(engine, two) == XTC_ERR_CAPACITY);
|
||||
CHECK(xtc_realtime_get_status(engine, &status) == XTC_OK && status.submitted_revision == 1U && status.active_revision == 0U);
|
||||
CHECK(xtc_realtime_process(engine, input, output, 4U) == XTC_OK && output[0] == 1.0f);
|
||||
CHECK(xtc_realtime_submit(engine, two) == XTC_OK);
|
||||
CHECK(xtc_realtime_process(engine, input, output, 4U) == XTC_OK && output[0] == 2.0f);
|
||||
xtc_realtime_collect(engine);
|
||||
CHECK(xtc_realtime_get_status(engine, &status) == XTC_OK && status.active_revision == 2U && status.submitted_revision == 2U);
|
||||
CHECK(xtc_realtime_process(engine, input, output, 0U) == XTC_OK && output[0] == 2.0f);
|
||||
CHECK(xtc_realtime_get_status(engine, &status) == XTC_OK && status.processed_blocks == 3U);
|
||||
state.engine = engine; state.stop = 0U; state.failed = 0U;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue