#include "xtc/xtc_engine.h" #include #include #include #define CHECK(c) do { if (!(c)) { fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, #c); return 1; } } while (0) #define NEAR(a,b) (fabsf((a) - (b)) < 0.00001f) static int oscillator(void) { xtc_graph *graph = NULL; xtc_plan *plan = NULL, *other = NULL; size_t osc, gain, meter, output, unused; float whole[19], split[19], peak; const float expected[4] = {0.0f, 0.25f, 0.0f, -0.25f}; size_t i; CHECK(xtc_graph_create(5U, &graph) == XTC_OK); /* Reverse insertion order forces real dependency scheduling. */ CHECK(xtc_graph_add_output(graph, &output) == XTC_OK); CHECK(xtc_graph_add_meter(graph, &meter) == XTC_OK); CHECK(xtc_graph_add_gain(graph, 0.25f, &gain) == XTC_OK); CHECK(xtc_graph_add_oscillator(graph, 12000.0f, &osc) == XTC_OK); CHECK(xtc_graph_connect(graph, osc, gain) == XTC_OK); CHECK(xtc_graph_connect(graph, gain, meter) == XTC_OK); CHECK(xtc_graph_connect(graph, meter, output) == XTC_OK); CHECK(xtc_graph_compile(graph, 48000.0, 19U, &plan) == XTC_OK); CHECK(xtc_graph_compile(graph, 48000.0, 19U, &other) == XTC_OK); CHECK(xtc_graph_add_gain(graph, 999.0f, &unused) == XTC_OK); xtc_graph_destroy(graph); /* Plans own their snapshot and lifetime. */ CHECK(xtc_plan_process(plan, NULL, whole, 19U) == XTC_OK); for (i = 0U; i < 19U; ++i) CHECK(NEAR(whole[i], expected[i % 4U])); CHECK(xtc_plan_meter_peak(plan, meter, &peak) == XTC_OK && NEAR(peak, 0.25f)); CHECK(xtc_plan_process(other, NULL, split, 3U) == XTC_OK); CHECK(xtc_plan_process(other, NULL, split + 3U, 7U) == XTC_OK); CHECK(xtc_plan_process(other, NULL, split + 10U, 9U) == XTC_OK); CHECK(memcmp(whole, split, sizeof(whole)) == 0); CHECK(xtc_plan_reset(other) == XTC_OK); CHECK(xtc_plan_meter_peak(other, meter, &peak) == XTC_OK && peak == 0.0f); split[0] = 42.0f; CHECK(xtc_plan_process(other, NULL, split, 20U) == XTC_ERR_CAPACITY); CHECK(split[0] == 42.0f); CHECK(xtc_plan_process(other, NULL, NULL, 1U) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_plan_process(other, NULL, split, 0U) == XTC_OK && split[0] == 42.0f); CHECK(xtc_plan_process(other, NULL, split, 19U) == XTC_OK); CHECK(memcmp(whole, split, sizeof(whole)) == 0); CHECK(xtc_plan_meter_peak(other, gain, &peak) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_plan_meter_peak(other, SIZE_MAX, &peak) == XTC_ERR_NOT_FOUND); xtc_plan_destroy(plan); xtc_plan_destroy(other); return 0; } static int routing(void) { xtc_graph *graph = NULL; xtc_plan *plan = NULL; size_t output, a, b, root, disconnected; float samples[4] = {1.0f, -1.0f, 0.5f, 0.0f}; CHECK(xtc_graph_create(5U, &graph) == XTC_OK); CHECK(xtc_graph_add_output(graph, &output) == XTC_OK); CHECK(xtc_graph_add_gain(graph, 2.0f, &a) == XTC_OK); CHECK(xtc_graph_add_gain(graph, 3.0f, &b) == XTC_OK); CHECK(xtc_graph_add_gain(graph, 0.5f, &root) == XTC_OK); CHECK(xtc_graph_add_gain(graph, 100.0f, &disconnected) == XTC_OK); CHECK(xtc_graph_connect(graph, root, a) == XTC_OK); CHECK(xtc_graph_connect(graph, root, b) == XTC_OK); CHECK(xtc_graph_connect(graph, a, output) == XTC_OK); CHECK(xtc_graph_connect(graph, b, output) == XTC_OK); CHECK(xtc_graph_compile(graph, 48000.0, 4U, &plan) == XTC_OK); CHECK(xtc_plan_process(plan, samples, samples, 4U) == XTC_OK); CHECK(NEAR(samples[0], 2.5f) && NEAR(samples[1], -2.5f) && NEAR(samples[2], 1.25f)); CHECK(xtc_plan_process(plan, NULL, samples, 4U) == XTC_OK); CHECK(samples[0] == 0.0f && samples[3] == 0.0f); samples[0] = NAN; samples[1] = INFINITY; CHECK(xtc_plan_process(plan, samples, samples, 4U) == XTC_OK); CHECK(samples[0] == 0.0f && samples[1] == 0.0f); xtc_plan_destroy(plan); xtc_graph_destroy(graph); return 0; } static int validation(void) { xtc_graph *graph = NULL; xtc_plan *plan = NULL; xtc_port_info port; size_t a, b, osc, output, unchanged = 77U; size_t iteration; 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_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); CHECK(xtc_graph_add_gain(graph, 1.0f, &b) == XTC_OK); CHECK(xtc_graph_add_oscillator(graph, 24000.0f, &osc) == XTC_OK); CHECK(xtc_graph_add_output(graph, &output) == XTC_OK); CHECK(xtc_graph_add_meter(graph, &unchanged) == XTC_ERR_CAPACITY && unchanged == 77U); CHECK(xtc_graph_connect(graph, a, a) == XTC_ERR_GRAPH_CYCLE); CHECK(xtc_graph_connect(graph, a, b) == XTC_OK); CHECK(xtc_graph_connect(graph, b, a) == XTC_ERR_GRAPH_CYCLE); CHECK(xtc_graph_connect(graph, a, b) == XTC_ERR_INVALID_STATE); CHECK(xtc_graph_connect(graph, SIZE_MAX, b) == XTC_ERR_NOT_FOUND); CHECK(xtc_graph_connect_ports(graph, a, 0U, b, 0U) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_graph_connect_ports(graph, a, 1U, b, 1U) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_graph_connect_ports(graph, a, 2U, b, 0U) == XTC_ERR_NOT_FOUND); CHECK(xtc_graph_connect(graph, a, osc) == XTC_ERR_NOT_FOUND); CHECK(xtc_graph_connect(graph, output, a) == XTC_ERR_NOT_FOUND); CHECK(xtc_graph_get_port(graph, osc, 1U, &port) == XTC_OK); CHECK(port.direction == XTC_PORT_OUTPUT && port.signal_type == XTC_SIGNAL_AUDIO && port.channel_count == 1U); CHECK(xtc_graph_validate(graph) == XTC_OK); CHECK(xtc_graph_compile(graph, NAN, 4U, &plan) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_graph_compile(graph, 0.0, 4U, &plan) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_graph_compile(graph, 44100.0, 4U, &plan) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_graph_compile(graph, 48000.0, SIZE_MAX, &plan) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_graph_compile(graph, 48000.0, 0U, &plan) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_graph_compile(NULL, 48000.0, 4U, &plan) == XTC_ERR_INVALID_ARGUMENT); CHECK(xtc_plan_reset(NULL) == XTC_ERR_INVALID_ARGUMENT); for (iteration = 0U; iteration < 100U; ++iteration) { CHECK(xtc_graph_compile(graph, 48000.0, 4U, &plan) == XTC_OK); xtc_plan_destroy(plan); } xtc_graph_destroy(graph); xtc_graph_destroy(NULL); xtc_plan_destroy(NULL); return 0; } int main(void) { CHECK(oscillator() == 0); CHECK(routing() == 0); CHECK(validation() == 0); puts("All offline graph tests passed."); return 0; }