84 lines
5.5 KiB
C
84 lines
5.5 KiB
C
#include "xtc/xtc_engine.h"
|
|
#include "xtc/xtc_realtime.h"
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
int main(void)
|
|
{
|
|
xtc_graph *graph = NULL, *inserted = NULL, *bad = NULL, *legacy = NULL, *full = NULL;
|
|
xtc_plan *old = NULL, *fresh = NULL;
|
|
xtc_realtime *engine = NULL;
|
|
xtc_graph_edit edit = {0};
|
|
xtc_routing_info info[256] = {{0}}, sentinel[256];
|
|
xtc_realtime_status status;
|
|
size_t source, gain, output, unused, added = SIZE_MAX, count = 999, nodes, edges, i;
|
|
float a[32], b[32];
|
|
assert(xtc_graph_create(8, &graph) == XTC_OK);
|
|
assert(xtc_graph_require_output_nodes(graph, 1) == XTC_OK);
|
|
assert(xtc_graph_add_oscillator(graph, 12000, &source) == XTC_OK);
|
|
assert(xtc_graph_add_gain(graph, 0.25f, &gain) == XTC_OK);
|
|
assert(xtc_graph_add_output(graph, &output) == XTC_OK);
|
|
assert(xtc_graph_add_meter(graph, &unused) == XTC_OK);
|
|
assert(xtc_graph_connect(graph, source, gain) == XTC_OK && xtc_graph_connect(graph, gain, output) == XTC_OK);
|
|
assert(xtc_graph_analyze(graph, info, 256, &count) == XTC_OK && count == 4);
|
|
assert(info[0].id == source && info[0].inputs == 0 && info[0].outputs == 1 && info[0].level == 0 && info[0].reaches_output && !info[0].external_input);
|
|
assert(info[1].inputs == 1 && info[1].outputs == 1 && info[1].level == 1 && info[1].reaches_output && !info[1].external_input);
|
|
assert(info[2].level == 2 && info[2].reaches_output && !info[2].external_input);
|
|
assert(!info[3].reaches_output && info[3].external_input);
|
|
memcpy(sentinel, info, sizeof(info)); count = 999;
|
|
assert(xtc_graph_analyze(graph, info, 3, &count) == XTC_ERR_CAPACITY && count == 999 && !memcmp(info, sentinel, sizeof(info)));
|
|
assert(xtc_graph_analyze(NULL, info, 256, &count) == XTC_ERR_INVALID_ARGUMENT);
|
|
assert(xtc_graph_analyze(graph, NULL, 256, &count) == XTC_ERR_INVALID_ARGUMENT);
|
|
edit.kind = XTC_EDIT_INSERT_GAIN;
|
|
edit.data.connection = (xtc_connection_info){source, 1, gain, 0};
|
|
assert(xtc_graph_apply_edit(graph, &edit, &inserted, &added) == XTC_OK && added > unused);
|
|
assert(xtc_graph_get_counts(graph, &nodes, &edges) == XTC_OK && nodes == 4 && edges == 2);
|
|
assert(xtc_graph_get_counts(inserted, &nodes, &edges) == XTC_OK && nodes == 5 && edges == 3);
|
|
assert(xtc_graph_analyze(inserted, info, 256, &count) == XTC_OK && count == 5);
|
|
assert(info[4].id == added && info[4].level == 1 && info[1].level == 2 && info[2].level == 3);
|
|
assert(xtc_graph_compile(graph, 48000, 32, &old) == XTC_OK);
|
|
assert(xtc_graph_compile(inserted, 48000, 32, &fresh) == XTC_OK);
|
|
assert(xtc_plan_process(old, NULL, a, 32) == XTC_OK && xtc_plan_process(fresh, NULL, b, 32) == XTC_OK && !memcmp(a, b, sizeof(a)));
|
|
xtc_plan_destroy(old); xtc_plan_destroy(fresh);
|
|
/* Missing/invalid wire never consumes IDs or returns a partial graph. */
|
|
size_t inserted_id = added;
|
|
added = 999;
|
|
edit.data.connection.destination_node = unused;
|
|
assert(xtc_graph_apply_edit(graph, &edit, &bad, &added) == XTC_ERR_NOT_FOUND && !bad && added == 999);
|
|
edit.data.connection = (xtc_connection_info){source, 0, gain, 0};
|
|
assert(xtc_graph_apply_edit(graph, &edit, &bad, &added) != XTC_OK && !bad && added == 999);
|
|
assert(xtc_graph_create(2, &full) == XTC_OK);
|
|
assert(xtc_graph_add_gain(full, 1, &source) == XTC_OK && xtc_graph_add_output(full, &output) == XTC_OK);
|
|
assert(xtc_graph_connect(full, source, output) == XTC_OK);
|
|
edit.data.connection = (xtc_connection_info){source, 1, output, 0};
|
|
assert(xtc_graph_apply_edit(full, &edit, &bad, &added) == XTC_ERR_CAPACITY && !bad && added == 999);
|
|
assert(xtc_graph_get_counts(full, &nodes, &edges) == XTC_OK && nodes == 2 && edges == 1);
|
|
xtc_graph_destroy(full);
|
|
/* Rejected cycle and disconnect leave an independently compiled plan usable. */
|
|
edit.kind = XTC_EDIT_CONNECT;
|
|
edit.data.connection = (xtc_connection_info){gain, 1, inserted_id, 0};
|
|
assert(xtc_graph_apply_edit(inserted, &edit, &bad, NULL) == XTC_ERR_GRAPH_CYCLE && !bad);
|
|
/* Pending/active plan handoff publishes the entire inserted chain at once. */
|
|
assert(xtc_realtime_create(48000, 32, &engine) == XTC_OK);
|
|
assert(xtc_realtime_submit(engine, graph) == XTC_OK);
|
|
assert(xtc_realtime_process(engine, NULL, a, 32) == XTC_OK);
|
|
for (i = 0; i < 100; ++i) {
|
|
assert(xtc_realtime_submit(engine, i % 2 ? graph : inserted) == XTC_OK);
|
|
assert(xtc_realtime_process(engine, NULL, b, 32) == XTC_OK && !memcmp(a, b, sizeof(a)));
|
|
xtc_realtime_collect(engine);
|
|
assert(xtc_realtime_get_status(engine, &status) == XTC_OK && status.active_revision == status.submitted_revision);
|
|
}
|
|
xtc_realtime_destroy(engine);
|
|
/* Legacy terminal fallback is disabled whenever an explicit output exists. */
|
|
assert(xtc_graph_create(4, &legacy) == XTC_OK);
|
|
assert(xtc_graph_add_gain(legacy, 1, &gain) == XTC_OK);
|
|
assert(xtc_graph_analyze(legacy, info, 256, &count) == XTC_OK && info[0].reaches_output && info[0].external_input);
|
|
assert(xtc_graph_add_output(legacy, &output) == XTC_OK);
|
|
assert(xtc_graph_analyze(legacy, info, 256, &count) == XTC_OK && !info[0].reaches_output && info[1].external_input);
|
|
assert(xtc_graph_connect(legacy, gain, output) == XTC_OK);
|
|
assert(xtc_graph_analyze(legacy, info, 256, &count) == XTC_OK && info[0].reaches_output && !info[1].external_input);
|
|
xtc_graph_destroy(legacy); xtc_graph_destroy(graph); xtc_graph_destroy(inserted);
|
|
puts("Routing reachability/levels/external input, atomic wire insertion/rollback and publication passed.");
|
|
return 0;
|
|
}
|