pipewire/spa/plugins/audioconvert/spa-resample-dump-coeffs.c

201 lines
4.8 KiB
C
Raw Normal View History

/* Spa */
/* SPDX-FileCopyrightText: Copyright © 2024 Arun Raghavan <arun@asymptotic.io> */
/* SPDX-License-Identifier: MIT */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <spa/support/log-impl.h>
#include <spa/utils/result.h>
#include <spa/utils/string.h>
SPA_LOG_IMPL(logger);
#include "resample.h"
#include "resample-native-impl.h"
#define OPTIONS "ht:"
static const struct option long_options[] = {
{ "help", no_argument, NULL, 'h'},
{ "tuple", required_argument, NULL, 't' },
{ NULL, 0, NULL, 0 }
};
static void show_usage(const char *name, bool is_error)
{
FILE *fp;
fp = is_error ? stderr : stdout;
fprintf(fp, "%s [options]\n", name);
fprintf(fp,
" -h, --help Show this help\n"
"\n"
" -t --tuple Sample rate tuple (as \"in_rate,out_rate[,quality]\")\n"
"\n");
}
static void parse_tuple(const char *arg, int *in, int *out, int *quality)
{
char tuple[256];
char *token;
strncpy(tuple, arg, sizeof(tuple) - 1);
*in = 0;
*out = 0;
token = strtok(tuple, ",");
if (!token || !spa_atoi32(token, in, 10))
return;
token = strtok(NULL, ",");
if (!token || !spa_atoi32(token, out, 10))
return;
token = strtok(NULL, ",");
if (!token) {
*quality = RESAMPLE_DEFAULT_QUALITY;
} else if (!spa_atoi32(token, quality, 10)) {
*quality = -1;
return;
}
/* first, second now contain zeroes on error, or the numbers on success,
* third contains a quality or -1 on error, default value if unspecified */
}
#define PREFIX "__precomp_coeff"
static void dump_header(void)
{
printf("/* This is a generated file, see spa-resample-dump-coeffs.c */");
printf("\n#include <stdint.h>\n");
printf("\n#include <stdlib.h>\n");
printf("\n");
printf("struct resample_coeffs {\n");
printf("\tuint32_t in_rate;\n");
printf("\tuint32_t out_rate;\n");
printf("\tint quality;\n");
printf("\tconst float *filter;\n");
printf("};\n");
}
static void dump_footer(const uint32_t *ins, const uint32_t *outs, const int *qualities)
{
printf("\n");
printf("static const struct resample_coeffs precomp_coeffs[] = {\n");
while (*ins && *outs) {
printf("\t{ .in_rate = %u, .out_rate = %u, .quality = %u, "
".filter = %s_%u_%u_%u },\n",
*ins, *outs, *qualities, PREFIX, *ins, *outs, *qualities);
ins++;
outs++;
qualities++;
}
printf("\t{ .in_rate = 0, .out_rate = 0, .quality = 0, .filter = NULL },\n");
printf("};\n");
}
static void dump_coeffs(unsigned int in_rate, unsigned int out_rate, int quality)
{
struct resample r = { 0, };
struct native_data *d;
unsigned int i, filter_size;
int ret;
r.log = &logger.log;
r.i_rate = in_rate;
r.o_rate = out_rate;
r.quality = quality;
r.channels = 1; /* irrelevant for generated taps */
if ((ret = resample_native_init(&r)) < 0) {
fprintf(stderr, "can't init converter: %s\n", spa_strerror(ret));
return;
}
d = r.data;
filter_size = d->filter_stride * (d->n_phases + 1);
printf("\n");
printf("static const float %s_%u_%u_%u[] = {", PREFIX, in_rate, out_rate, quality);
for (i = 0; i < filter_size; i++) {
printf("%a", d->filter[i]);
if (i != filter_size - 1)
printf(",");
}
printf("};\n");
if (r.free)
r.free(&r);
}
int main(int argc, char* argv[])
{
unsigned int ins[256] = { 0, }, outs[256] = { 0, };
int qualities[256] = { 0, };
int in_rate = 0, out_rate = 0, quality = 0;
int c, longopt_index = 0, i = 0;
while ((c = getopt_long(argc, argv, OPTIONS, long_options, &longopt_index)) != -1) {
switch (c) {
case 'h':
show_usage(argv[0], false);
return EXIT_SUCCESS;
case 't':
parse_tuple(optarg, &in_rate, &out_rate, &quality);
if (in_rate <= 0) {
fprintf(stderr, "error: bad input rate %d\n", in_rate);
goto error;
}
if (out_rate <= 0) {
fprintf(stderr, "error: bad output rate %d\n", out_rate);
goto error;
}
if (quality < 0 || quality > 14) {
fprintf(stderr, "error: bad quality value %s\n", optarg);
goto error;
}
ins[i] = in_rate;
outs[i] = out_rate;
qualities[i] = quality;
i++;
break;
default:
fprintf(stderr, "error: unknown option\n");
goto error_usage;
}
}
if (optind != argc) {
fprintf(stderr, "error: got %d extra argument(s))\n",
optind - argc);
goto error_usage;
}
if (in_rate == 0) {
fprintf(stderr, "error: input rate must be specified\n");
goto error;
}
if (out_rate == 0) {
fprintf(stderr, "error: input rate must be specified\n");
goto error;
}
dump_header();
while (i--) {
dump_coeffs(ins[i], outs[i], qualities[i]);
}
dump_footer(ins, outs, qualities);
return EXIT_SUCCESS;
error_usage:
show_usage(argv[0], true);
error:
return EXIT_FAILURE;
}