-/*
- * Copyright (C) 2012-2014 Andre Noll <maan@systemlinux.org>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 2012 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
/** \file resample_filter.c A sample rate converter based on libsamplerate. */
#include <regex.h>
#include <samplerate.h>
+#include <lopsub.h>
-#include "resample_filter.cmdline.h"
+#include "filter_cmd.lsg.h"
#include "para.h"
#include "error.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "string.h"
#include "check_wav.h"
+#define U32_OPTVAL(_opt, _lpr) (FILTER_CMD_OPT_UINT32_VAL(RESAMPLE, _opt, _lpr))
+#define OPT_GIVEN(_opt, _lpr) (FILTER_CMD_OPT_GIVEN(RESAMPLE, _opt, _lpr))
+
+/* effective values, may differ from config arg */
struct resample_context {
- int channels;
+ uint32_t channels;
int source_sample_rate;
float ratio;
SRC_STATE *src_state;
{
struct filter_node *fn = btr_context(btrn);
struct resample_context *ctx = fn->private_data;
- struct resample_filter_args_info *conf = fn->conf;
-
- return decoder_execute(cmd, conf->dest_sample_rate_arg, ctx->channels,
- result);
+ uint32_t dsr = U32_OPTVAL(DEST_SAMPLE_RATE, fn->lpr);
+ return decoder_execute(cmd, dsr, ctx->channels, result);
}
static void resample_close(struct filter_node *fn)
static void resample_open(struct filter_node *fn)
{
- struct resample_context *ctx = para_calloc(sizeof(*ctx));
- struct resample_filter_args_info *conf = fn->conf;
+ struct resample_context *ctx = zalloc(sizeof(*ctx));
struct btr_node *btrn = fn->btrn;
struct wav_params wp;
fn->private_data = ctx;
fn->min_iqs = 2;
- COPY_WAV_PARMS(&wp, conf);
+ LLS_COPY_WAV_PARMS(&wp, LSG_FILTER_CMD_RESAMPLE, fn->lpr);
ctx->cwc = check_wav_init(btr_parent(btrn), btrn, &wp, NULL);
btr_log_tree(btr_parent(btr_parent(btrn)), LL_INFO);
}
-static void resample_pre_select(struct sched *s, struct task *t)
+static void resample_pre_monitor(struct sched *s, void *context)
{
- struct filter_node *fn = container_of(t, struct filter_node, task);
+ struct filter_node *fn = context;
struct resample_context *ctx = fn->private_data;
int ret = btr_node_status(fn->btrn, fn->min_iqs, BTR_NT_INTERNAL);
if (ret != 0)
return sched_min_delay(s);
- check_wav_pre_select(s, ctx->cwc);
+ check_wav_pre_monitor(s, ctx->cwc);
}
static int get_btr_val(const char *what, struct btr_node *btrn)
{
int ret;
struct resample_context *ctx = fn->private_data;
- struct resample_filter_args_info *conf = fn->conf;
struct btr_node *btrn = fn->btrn;
+ struct lls_parse_result *lpr = fn->lpr;
- ctx->channels = conf->channels_arg;
- if (!conf->channels_given) {
+ ctx->channels = U32_OPTVAL(CHANNELS, lpr);
+ if (!OPT_GIVEN(CHANNELS, lpr)) {
ret = get_btr_val("channels", btrn);
if (ret >= 0)
ctx->channels = ret;
}
-
- ctx->source_sample_rate = conf->sample_rate_arg;
- if (!conf->sample_rate_given) {
+ ctx->source_sample_rate = U32_OPTVAL(SAMPLE_RATE, lpr);
+ if (!OPT_GIVEN(SAMPLE_RATE, lpr)) {
ret = get_btr_val("sample_rate", btrn);
if (ret >= 0)
ctx->source_sample_rate = ret;
/* reject all sample formats except 16 bit signed, little endian */
ret = get_btr_val("sample_format", btrn);
if (ret >= 0 && ret != SF_S16_LE) {
- const char *sample_formats[] = {SAMPLE_FORMATS};
+ const char * const sample_formats[] = {SAMPLE_FORMATS};
PARA_ERROR_LOG("unsupported sample format: %s\n",
sample_formats[ret]);
return -ERRNO_TO_PARA_ERROR(EINVAL);
}
- ctx->ratio = (float)conf->dest_sample_rate_arg / ctx->source_sample_rate;
+ ctx->ratio = U32_OPTVAL(DEST_SAMPLE_RATE, lpr)
+ / (float)ctx->source_sample_rate;
return 1;
}
static int resample_init(struct filter_node *fn)
{
- int ret, converter;
+ int ret;
+ const uint32_t trafo[] = {
+ [RCT_BEST] = SRC_SINC_BEST_QUALITY,
+ [RCT_MEDIUM] = SRC_SINC_MEDIUM_QUALITY,
+ [RCT_FASTEST] = SRC_SINC_FASTEST,
+ [RCT_ZERO_ORDER_HOLD] = SRC_ZERO_ORDER_HOLD,
+ [RCT_LINEAR] = SRC_LINEAR
+ };
struct resample_context *ctx = fn->private_data;
- struct resample_filter_args_info *conf = fn->conf;
- struct btr_node *btrn = fn->btrn;
+ const struct lls_option *o_c = FILTER_CMD_OPT(RESAMPLE, CONVERTER);
+ uint32_t converter = U32_OPTVAL(CONVERTER, fn->lpr);
- ret = -E_RESAMPLE_EOF;
- if (btr_no_parent(btrn))
- return ret;
- if (btr_get_input_queue_size(btrn) == 0)
- return 0;
+ PARA_INFO_LOG("converter type: %s\n",
+ lls_enum_string_val(converter, o_c));
ret = resample_set_params(fn);
if (ret < 0)
return ret;
- switch (conf->converter_arg) {
- case converter_arg_best:
- converter = SRC_SINC_BEST_QUALITY;
- break;
- case converter_arg_medium:
- converter = SRC_SINC_MEDIUM_QUALITY;
- break;
- case converter_arg_fastest:
- converter = SRC_SINC_FASTEST;
- break;
- case converter_arg_zero_order_hold:
- converter = SRC_ZERO_ORDER_HOLD;
- break;
- case converter_arg_linear:
- converter = SRC_LINEAR;
- break;
- default:
- assert(0);
- }
- ctx->src_state = src_new(converter, conf->channels_arg, &ret);
+ ctx->src_state = src_new(trafo[converter],
+ U32_OPTVAL(CHANNELS, fn->lpr), &ret);
if (!ctx->src_state) {
PARA_ERROR_LOG("%s\n", src_strerror(ret));
return -E_LIBSAMPLERATE;
size_t *result_frames)
{
int ret, num_samples, out_samples;
+ float *in_float;
int16_t *out;
SRC_DATA data;
data.output_frames = num_frames * ctx->ratio + 1;
out_samples = data.output_frames * ctx->channels;
- data.data_in = para_malloc(num_samples * sizeof(float));
- src_short_to_float_array(in, data.data_in, num_samples);
- data.data_out = para_malloc(out_samples * sizeof(float));
+ in_float = arr_alloc(num_samples, sizeof(float));
+ src_short_to_float_array(in, in_float, num_samples);
+ data.data_in = in_float;
+ data.data_out = arr_alloc(out_samples, sizeof(float));
ret = src_process(ctx->src_state, &data);
- free(data.data_in);
+ free(in_float);
if (ret != 0) {
PARA_ERROR_LOG("%s\n", src_strerror(ret));
free(data.data_out);
return -E_LIBSAMPLERATE;
}
out_samples = data.output_frames_gen * ctx->channels;
- out = para_malloc(out_samples * sizeof(short));
+ out = arr_alloc(out_samples, sizeof(short));
src_float_to_short_array(data.data_out, out, out_samples);
free(data.data_out);
*result = out;
return data.input_frames_used;
}
-static int resample_post_select(__a_unused struct sched *s, struct task *t)
+static int resample_post_monitor(__a_unused struct sched *s, void *context)
{
int ret;
- struct filter_node *fn = container_of(t, struct filter_node, task);
+ struct filter_node *fn = context;
struct resample_context *ctx = fn->private_data;
- struct resample_filter_args_info *conf = fn->conf;
struct btr_node *btrn = fn->btrn;
int16_t *in, *out;
size_t in_bytes, num_frames;
bool have_more;
- ret = check_wav_post_select(ctx->cwc);
+ ret = check_wav_post_monitor(ctx->cwc);
if (ret < 0)
goto out;
+ ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
+ if (ret <= 0)
+ goto out;
if (!ctx->src_state) {
ret = resample_init(fn);
if (ret <= 0)
goto out;
}
- ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
- if (ret <= 0)
- goto out;
- if (ctx->source_sample_rate == conf->dest_sample_rate_arg) {
+ if (ctx->source_sample_rate == U32_OPTVAL(DEST_SAMPLE_RATE, fn->lpr)) {
/*
* No resampling necessary. We do not splice ourselves out
* though, since our children might want to ask us through the
if (ret < 0) {
btr_remove_node(&fn->btrn);
/* This releases the check_wav btr node */
- check_wav_post_select(ctx->cwc);
+ check_wav_post_monitor(ctx->cwc);
}
return ret;
}
-static int resample_parse_config(int argc, char **argv, void **config)
+static void *resample_setup(const struct lls_parse_result *lpr)
{
- int ret, val, given;
- struct resample_filter_args_info *conf = para_calloc(sizeof(*conf));
-
- resample_filter_cmdline_parser(argc, argv, conf);
+ int given;
+ uint32_t u32;
/* sanity checks */
- ret = -ERRNO_TO_PARA_ERROR(EINVAL);
- val = conf->channels_arg;
- given = conf->channels_given;
- if (val < 0 || (val == 0 && given))
- goto err;
- val = conf->sample_rate_arg;
- given = conf->sample_rate_given;
- if (val < 0 || (val == 0 && given))
- goto err;
- val = conf->dest_sample_rate_arg;
- given = conf->dest_sample_rate_given;
- if (val < 0 || (val == 0 && given))
- goto err;
- *config = conf;
- return 1;
-err:
- free(conf);
- return ret;
+ u32 = U32_OPTVAL(CHANNELS, lpr);
+ given = OPT_GIVEN(CHANNELS, lpr);
+ if (u32 == 0 && given) {
+ PARA_EMERG_LOG("fatal: zero channels?!\n");
+ exit(EXIT_FAILURE);
+ }
+ u32 = U32_OPTVAL(SAMPLE_RATE, lpr);
+ given = OPT_GIVEN(SAMPLE_RATE, lpr);
+ if (u32 == 0 && given) {
+ PARA_EMERG_LOG("fatal: input sample rate can not be 0\n");
+ exit(EXIT_FAILURE);
+ }
+ u32 = U32_OPTVAL(DEST_SAMPLE_RATE, lpr);
+ given = OPT_GIVEN(DEST_SAMPLE_RATE, lpr);
+ if (u32 == 0 && given) {
+ PARA_EMERG_LOG("fatal: destination sample rate can not be 0\n");
+ exit(EXIT_FAILURE);
+ }
+ return NULL;
}
-static void resample_free_config(void *conf)
+static void resample_teardown(__a_unused const struct lls_parse_result *lpr,
+ void *conf)
{
- if (!conf)
- return;
- resample_filter_cmdline_parser_free(conf);
free(conf);
}
-/**
- * The init function of the resample filter.
- *
- * \param f Structure to initialize.
- */
-void resample_filter_init(struct filter *f)
-{
- struct resample_filter_args_info dummy;
-
- resample_filter_cmdline_parser_init(&dummy);
- f->close = resample_close;
- f->open = resample_open;
- f->pre_select = resample_pre_select;
- f->post_select = resample_post_select;
- f->parse_config = resample_parse_config;
- f->free_config = resample_free_config;
- f->execute = resample_execute;
- f->help = (struct ggo_help)DEFINE_GGO_HELP(resample_filter);
-}
+const struct filter lsg_filter_cmd_com_resample_user_data = {
+ .setup = resample_setup,
+ .open = resample_open,
+ .pre_monitor = resample_pre_monitor,
+ .post_monitor = resample_post_monitor,
+ .close = resample_close,
+ .teardown = resample_teardown,
+ .execute = resample_execute
+};