mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-22 06:59:59 -05:00
resample: add some more options to spa-resample
Make it possible to set the params by name. Dump the resampler config in verbose mode.
This commit is contained in:
parent
e8268969ea
commit
faf4641625
3 changed files with 69 additions and 30 deletions
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
SPA_LOG_TOPIC_DEFINE(resample_log_topic, "spa.resample");
|
SPA_LOG_TOPIC_DEFINE(resample_log_topic, "spa.resample");
|
||||||
|
|
||||||
|
#define INHERIT_PARAM(c,q,p) if ((c)->params[p] == 0.0) (c)->params[p] = (q)->params[p];
|
||||||
|
|
||||||
struct quality {
|
struct quality {
|
||||||
uint32_t n_taps;
|
uint32_t n_taps;
|
||||||
double cutoff_up; /* when upsampling */
|
double cutoff_up; /* when upsampling */
|
||||||
|
|
@ -20,6 +22,7 @@ struct quality {
|
||||||
double params[RESAMPLE_MAX_PARAMS];
|
double params[RESAMPLE_MAX_PARAMS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct window_info {
|
struct window_info {
|
||||||
uint32_t window;
|
uint32_t window;
|
||||||
void (*func) (struct resample *r, double *w, double t, uint32_t n_taps);
|
void (*func) (struct resample *r, double *w, double t, uint32_t n_taps);
|
||||||
|
|
@ -60,9 +63,7 @@ static inline void blackman_window(struct resample *r, double *w, double t, uint
|
||||||
static inline void blackman_config(struct resample *r)
|
static inline void blackman_config(struct resample *r)
|
||||||
{
|
{
|
||||||
const struct quality *q = &window_info[r->config.window].qualities[r->quality];
|
const struct quality *q = &window_info[r->config.window].qualities[r->quality];
|
||||||
const uint32_t p0 = RESAMPLE_PARAM_BLACKMAN_ALPHA;
|
INHERIT_PARAM(&r->config, q, RESAMPLE_PARAM_BLACKMAN_ALPHA);
|
||||||
if (r->config.params[p0] == 0.0)
|
|
||||||
r->config.params[p0] = q->params[p0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct quality exp_qualities[] = {
|
static const struct quality exp_qualities[] = {
|
||||||
|
|
@ -97,9 +98,7 @@ static inline void exp_window(struct resample *r, double *w, double t, uint32_t
|
||||||
static inline void exp_config(struct resample *r)
|
static inline void exp_config(struct resample *r)
|
||||||
{
|
{
|
||||||
const struct quality *q = &window_info[r->config.window].qualities[r->quality];
|
const struct quality *q = &window_info[r->config.window].qualities[r->quality];
|
||||||
const uint32_t p0 = RESAMPLE_PARAM_EXP_A;
|
INHERIT_PARAM(&r->config, q, RESAMPLE_PARAM_EXP_A);
|
||||||
if (r->config.params[p0] == 0.0)
|
|
||||||
r->config.params[p0] = q->params[p0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "dbesi0.c"
|
#include "dbesi0.c"
|
||||||
|
|
@ -166,9 +165,9 @@ static inline void kaiser_config(struct resample *r)
|
||||||
static inline void kaiser_config(struct resample *r)
|
static inline void kaiser_config(struct resample *r)
|
||||||
{
|
{
|
||||||
const struct quality *q = &window_info[r->config.window].qualities[r->quality];
|
const struct quality *q = &window_info[r->config.window].qualities[r->quality];
|
||||||
const uint32_t p0 = RESAMPLE_PARAM_KAISER_ALPHA;
|
INHERIT_PARAM(&r->config, q, RESAMPLE_PARAM_KAISER_ALPHA);
|
||||||
if (r->config.params[p0] == 0.0)
|
INHERIT_PARAM(&r->config, q, RESAMPLE_PARAM_KAISER_SB_ATT);
|
||||||
r->config.params[p0] = q->params[p0];
|
INHERIT_PARAM(&r->config, q, RESAMPLE_PARAM_KAISER_TR_BW);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <spa/support/log.h>
|
#include <spa/support/log.h>
|
||||||
|
|
||||||
#define RESAMPLE_DEFAULT_QUALITY 4
|
#define RESAMPLE_DEFAULT_QUALITY 4
|
||||||
|
#define RESAMPLE_WINDOW_DEFAULT RESAMPLE_WINDOW_EXP
|
||||||
#define RESAMPLE_MAX_PARAMS 16
|
#define RESAMPLE_MAX_PARAMS 16
|
||||||
|
|
||||||
struct resample_config {
|
struct resample_config {
|
||||||
|
|
@ -77,13 +78,14 @@ static const struct resample_window_info {
|
||||||
uint32_t window;
|
uint32_t window;
|
||||||
const char *label;
|
const char *label;
|
||||||
const char *description;
|
const char *description;
|
||||||
|
uint32_t n_params;
|
||||||
} resample_window_info[] = {
|
} resample_window_info[] = {
|
||||||
[RESAMPLE_WINDOW_EXP] = { RESAMPLE_WINDOW_EXP,
|
[RESAMPLE_WINDOW_EXP] = { RESAMPLE_WINDOW_EXP,
|
||||||
"exponential", "Exponential window", },
|
"exp", "Exponential window", 1 },
|
||||||
[RESAMPLE_WINDOW_BLACKMAN] = { RESAMPLE_WINDOW_BLACKMAN,
|
[RESAMPLE_WINDOW_BLACKMAN] = { RESAMPLE_WINDOW_BLACKMAN,
|
||||||
"blackman", "Blackman window", },
|
"blackman", "Blackman window", 1 },
|
||||||
[RESAMPLE_WINDOW_KAISER] = { RESAMPLE_WINDOW_KAISER,
|
[RESAMPLE_WINDOW_KAISER] = { RESAMPLE_WINDOW_KAISER,
|
||||||
"kaiser", "Kaiser window", },
|
"kaiser", "Kaiser window", 3 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint32_t resample_window_from_label(const char *label)
|
static inline uint32_t resample_window_from_label(const char *label)
|
||||||
|
|
@ -95,15 +97,21 @@ static inline uint32_t resample_window_from_label(const char *label)
|
||||||
return RESAMPLE_WINDOW_EXP;
|
return RESAMPLE_WINDOW_EXP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline const char *resample_window_name(uint32_t idx)
|
||||||
|
{
|
||||||
|
return resample_window_info[SPA_CLAMP(idx, 0u, SPA_N_ELEMENTS(resample_window_info)-1)].label;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct resample_param_info {
|
static const struct resample_param_info {
|
||||||
|
uint32_t window;
|
||||||
uint32_t idx;
|
uint32_t idx;
|
||||||
const char *label;
|
const char *label;
|
||||||
} resample_param_info[] = {
|
} resample_param_info[] = {
|
||||||
{ RESAMPLE_PARAM_EXP_A, "exp.A" },
|
{ RESAMPLE_WINDOW_EXP, RESAMPLE_PARAM_EXP_A, "exp.A" },
|
||||||
{ RESAMPLE_PARAM_BLACKMAN_ALPHA, "blackman.alpha" },
|
{ RESAMPLE_WINDOW_BLACKMAN, RESAMPLE_PARAM_BLACKMAN_ALPHA, "blackman.alpha" },
|
||||||
{ RESAMPLE_PARAM_KAISER_ALPHA, "kaiser.alpha" },
|
{ RESAMPLE_WINDOW_KAISER, RESAMPLE_PARAM_KAISER_ALPHA, "kaiser.alpha" },
|
||||||
{ RESAMPLE_PARAM_KAISER_SB_ATT, "kaiser.stopband-attenuation" },
|
{ RESAMPLE_WINDOW_KAISER, RESAMPLE_PARAM_KAISER_SB_ATT, "kaiser.stopband-attenuation" },
|
||||||
{ RESAMPLE_PARAM_KAISER_TR_BW, "kaiser.transition-bandwidth" },
|
{ RESAMPLE_WINDOW_KAISER, RESAMPLE_PARAM_KAISER_TR_BW, "kaiser.transition-bandwidth" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint32_t resample_param_from_label(const char *label)
|
static inline uint32_t resample_param_from_label(const char *label)
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,7 @@ struct data {
|
||||||
int format;
|
int format;
|
||||||
uint32_t window;
|
uint32_t window;
|
||||||
int quality;
|
int quality;
|
||||||
uint32_t n_taps;
|
struct resample_config config;
|
||||||
double params[4];
|
|
||||||
int cpu_flags;
|
int cpu_flags;
|
||||||
|
|
||||||
const char *iname;
|
const char *iname;
|
||||||
|
|
@ -65,6 +64,7 @@ static const struct option long_options[] = {
|
||||||
static void show_usage(const char *name, bool is_error)
|
static void show_usage(const char *name, bool is_error)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
fp = is_error ? stderr : stdout;
|
fp = is_error ? stderr : stdout;
|
||||||
|
|
||||||
|
|
@ -76,13 +76,27 @@ static void show_usage(const char *name, bool is_error)
|
||||||
fprintf(fp,
|
fprintf(fp,
|
||||||
" -r --rate Output sample rate (default as input)\n"
|
" -r --rate Output sample rate (default as input)\n"
|
||||||
" -f --format Output sample format %s (default as input)\n"
|
" -f --format Output sample format %s (default as input)\n"
|
||||||
" -w --window Window function blackman, exp, kaiser (default kaiser)\n"
|
|
||||||
" -q --quality Resampler quality (default %u)\n"
|
" -q --quality Resampler quality (default %u)\n"
|
||||||
" -p --param Resampler param\n"
|
" -w --window Window function (default %s)\n",
|
||||||
" -t --taps Resampler taps\n"
|
STR_FMTS, DEFAULT_QUALITY, resample_window_name(RESAMPLE_WINDOW_DEFAULT));
|
||||||
|
for (i = 0; i < SPA_N_ELEMENTS(resample_window_info); i++) {
|
||||||
|
fprintf(fp,
|
||||||
|
" %s: %s\n",
|
||||||
|
resample_window_info[i].label,
|
||||||
|
resample_window_info[i].description);
|
||||||
|
}
|
||||||
|
fprintf(fp,
|
||||||
|
" -t --taps Resampler taps (default from quality)\n"
|
||||||
|
" -p --param Resampler param <name>=<value> (default from quality)\n");
|
||||||
|
|
||||||
|
for (i = 0; i < SPA_N_ELEMENTS(resample_param_info); i++) {
|
||||||
|
fprintf(fp,
|
||||||
|
" %s\n",
|
||||||
|
resample_param_info[i].label);
|
||||||
|
}
|
||||||
|
fprintf(fp,
|
||||||
" -c --cpuflags CPU flags (default 0)\n"
|
" -c --cpuflags CPU flags (default 0)\n"
|
||||||
"\n",
|
"\n");
|
||||||
STR_FMTS, DEFAULT_QUALITY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const char *
|
static inline const char *
|
||||||
|
|
@ -216,13 +230,23 @@ static int do_conversion(struct data *d)
|
||||||
r.i_rate = d->iinfo.samplerate;
|
r.i_rate = d->iinfo.samplerate;
|
||||||
r.o_rate = d->oinfo.samplerate;
|
r.o_rate = d->oinfo.samplerate;
|
||||||
r.quality = d->quality < 0 ? DEFAULT_QUALITY : d->quality;
|
r.quality = d->quality < 0 ? DEFAULT_QUALITY : d->quality;
|
||||||
r.config.window = d->window;
|
r.config = d->config;
|
||||||
r.config.n_taps = d->n_taps;
|
|
||||||
r.config.params[0] = d->params[0];
|
|
||||||
if ((res = resample_native_init(&r)) < 0) {
|
if ((res = resample_native_init(&r)) < 0) {
|
||||||
fprintf(stderr, "can't init converter: %s\n", spa_strerror(res));
|
fprintf(stderr, "can't init converter: %s\n", spa_strerror(res));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
if (d->verbose) {
|
||||||
|
fprintf(stdout, "window:%s cutoff:%f n_taps:%u\n",
|
||||||
|
resample_window_name(r.config.window),
|
||||||
|
r.config.cutoff, r.config.n_taps);
|
||||||
|
for (i = 0; i < SPA_N_ELEMENTS(resample_param_info); i++) {
|
||||||
|
if (resample_param_info[i].window != r.config.window)
|
||||||
|
continue;
|
||||||
|
fprintf(stdout, " param:%s %f\n",
|
||||||
|
resample_param_info[i].label,
|
||||||
|
r.config.params[resample_param_info[i].idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (j = 0; j < channels; j++)
|
for (j = 0; j < channels; j++)
|
||||||
src[j] = &in[MAX_SAMPLES * j];
|
src[j] = &in[MAX_SAMPLES * j];
|
||||||
|
|
@ -333,13 +357,21 @@ int main(int argc, char *argv[])
|
||||||
data.cpu_flags = strtol(optarg, NULL, 0);
|
data.cpu_flags = strtol(optarg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
data.window = resample_window_from_label(optarg);
|
data.config.window = resample_window_from_label(optarg);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
data.params[0] = atof(optarg);
|
{
|
||||||
|
char *eq;
|
||||||
|
if ((eq = strchr(optarg, '=')) != NULL) {
|
||||||
|
uint32_t idx;
|
||||||
|
*eq = 0;
|
||||||
|
idx = resample_param_from_label(optarg);
|
||||||
|
data.config.params[idx] = atof(eq+1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 't':
|
case 't':
|
||||||
data.n_taps = atoi(optarg);
|
data.config.n_taps = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "error: unknown option '%c'\n", c);
|
fprintf(stderr, "error: unknown option '%c'\n", c);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue