1
0
Fork 0
forked from hanez/xtc
xtc/tests/unit/test_offline.c

166 lines
8 KiB
C

#include "xtc/xtc_engine.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#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;
}
/* External mono input is read by both channels, including when left aliases it. */
static int stereo_alias(void)
{
xtc_graph *graph = NULL;
xtc_plan *plan = NULL;
size_t gain, audio, output, i;
float left[4] = {1, 2, 3, 4}, right[4];
CHECK(xtc_graph_create(3, &graph) == XTC_OK);
CHECK(xtc_graph_add_gain(graph, 2, &gain) == XTC_OK);
CHECK(xtc_graph_add_audio(graph, &audio) == XTC_OK);
CHECK(xtc_graph_add_output(graph, &output) == XTC_OK);
CHECK(xtc_graph_connect(graph, gain, output) == XTC_OK);
CHECK(xtc_graph_connect(graph, audio, output) == XTC_OK);
CHECK(xtc_graph_compile(graph, 48000, 4, &plan) == XTC_OK);
CHECK(xtc_plan_process_stereo(plan, left, NULL, NULL, NULL, NULL, left, right, 4) == XTC_OK);
for (i = 0; i < 4; ++i)
CHECK(left[i] == 2 * (float)(i + 1) && right[i] == left[i]);
for (i = 0; i < 4; ++i) right[i] = 10 + (float)i;
/* Cross-channel source alias must also retain the original source samples. */
CHECK(xtc_plan_process_stereo(plan, NULL, right, left, NULL, NULL, left, right, 4) == XTC_OK);
for (i = 0; i < 4; ++i)
CHECK(left[i] == 10 + (float)i && right[i] == 2 * (float)(i + 1));
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);
CHECK(stereo_alias() == 0);
puts("All offline graph tests passed.");
return 0;
}