afh_common.c: Avoid ifdefs.
[paraslash.git] / resample_filter.c
1 /*
2  * Copyright (C) 2012 Andre Noll <maan@tuebingen.mpg.de>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file resample_filter.c A sample rate converter based on libsamplerate. */
8
9 #include <regex.h>
10 #include <samplerate.h>
11
12 #include "resample_filter.cmdline.h"
13 #include "para.h"
14 #include "error.h"
15 #include "list.h"
16 #include "sched.h"
17 #include "ggo.h"
18 #include "buffer_tree.h"
19 #include "filter.h"
20 #include "string.h"
21 #include "check_wav.h"
22
23 struct resample_context {
24         int channels;
25         int source_sample_rate;
26         float ratio;
27         SRC_STATE *src_state;
28         struct check_wav_context *cwc;
29 };
30
31 static int resample_execute(struct btr_node *btrn, const char *cmd, char **result)
32 {
33         struct filter_node *fn = btr_context(btrn);
34         struct resample_context *ctx = fn->private_data;
35         struct resample_filter_args_info *conf = fn->conf;
36
37         return decoder_execute(cmd, conf->dest_sample_rate_arg, ctx->channels,
38                 result);
39 }
40
41 static void resample_close(struct filter_node *fn)
42 {
43         struct resample_context *ctx = fn->private_data;
44
45         if (!ctx)
46                 return;
47         check_wav_shutdown(ctx->cwc);
48         if (ctx->src_state)
49                 src_delete(ctx->src_state);
50         free(ctx);
51         fn->private_data = NULL;
52 }
53
54 static void resample_open(struct filter_node *fn)
55 {
56         struct resample_context *ctx = para_calloc(sizeof(*ctx));
57         struct resample_filter_args_info *conf = fn->conf;
58         struct btr_node *btrn = fn->btrn;
59         struct wav_params wp;
60
61         fn->private_data = ctx;
62         fn->min_iqs = 2;
63         COPY_WAV_PARMS(&wp, conf);
64         ctx->cwc = check_wav_init(btr_parent(btrn), btrn, &wp, NULL);
65         btr_log_tree(btr_parent(btr_parent(btrn)), LL_INFO);
66 }
67
68 static void resample_pre_select(struct sched *s, void *context)
69 {
70         struct filter_node *fn = context;
71         struct resample_context *ctx = fn->private_data;
72         int ret = btr_node_status(fn->btrn, fn->min_iqs, BTR_NT_INTERNAL);
73
74         if (ret != 0)
75                 return sched_min_delay(s);
76         check_wav_pre_select(s, ctx->cwc);
77 }
78
79 static int get_btr_val(const char *what, struct btr_node *btrn)
80 {
81         char *buf;
82         int32_t val;
83         int ret = btr_exec_up(btr_parent(btrn), what, &buf);
84
85         if (ret < 0) {
86                 PARA_NOTICE_LOG("btr exec for \"%s\" failed\n", what);
87                 return ret;
88         }
89         ret = para_atoi32(buf, &val);
90         free(buf);
91         return ret < 0? ret : val;
92 }
93
94 static int resample_set_params(struct filter_node *fn)
95 {
96         int ret;
97         struct resample_context *ctx = fn->private_data;
98         struct resample_filter_args_info *conf = fn->conf;
99         struct btr_node *btrn = fn->btrn;
100
101         ctx->channels = conf->channels_arg;
102         if (!conf->channels_given) {
103                 ret = get_btr_val("channels", btrn);
104                 if (ret >= 0)
105                         ctx->channels = ret;
106         }
107
108         ctx->source_sample_rate = conf->sample_rate_arg;
109         if (!conf->sample_rate_given) {
110                 ret = get_btr_val("sample_rate", btrn);
111                 if (ret >= 0)
112                         ctx->source_sample_rate = ret;
113         }
114         /* reject all sample formats except 16 bit signed, little endian */
115         ret = get_btr_val("sample_format", btrn);
116         if (ret >= 0 && ret != SF_S16_LE) {
117                 const char *sample_formats[] = {SAMPLE_FORMATS};
118                 PARA_ERROR_LOG("unsupported sample format: %s\n",
119                         sample_formats[ret]);
120                 return -ERRNO_TO_PARA_ERROR(EINVAL);
121         }
122         ctx->ratio = (float)conf->dest_sample_rate_arg / ctx->source_sample_rate;
123         return 1;
124 }
125
126 static int resample_init(struct filter_node *fn)
127 {
128         int ret, converter;
129         struct resample_context *ctx = fn->private_data;
130         struct resample_filter_args_info *conf = fn->conf;
131         struct btr_node *btrn = fn->btrn;
132
133         ret = -E_RESAMPLE_EOF;
134         if (btr_no_parent(btrn))
135                 return ret;
136         if (btr_get_input_queue_size(btrn) == 0)
137                 return 0;
138         ret = resample_set_params(fn);
139         if (ret < 0)
140                 return ret;
141         switch (conf->converter_arg) {
142         case converter_arg_best:
143                 converter = SRC_SINC_BEST_QUALITY;
144                 break;
145         case converter_arg_medium:
146                 converter = SRC_SINC_MEDIUM_QUALITY;
147                 break;
148         case converter_arg_fastest:
149                 converter = SRC_SINC_FASTEST;
150                 break;
151         case converter_arg_zero_order_hold:
152                 converter = SRC_ZERO_ORDER_HOLD;
153                 break;
154         case converter_arg_linear:
155                 converter = SRC_LINEAR;
156                 break;
157         default:
158                 assert(0);
159         }
160         ctx->src_state = src_new(converter, conf->channels_arg, &ret);
161         if (!ctx->src_state) {
162                 PARA_ERROR_LOG("%s\n", src_strerror(ret));
163                 return -E_LIBSAMPLERATE;
164         }
165         fn->min_iqs = 2 * ctx->channels;
166         return 1;
167 }
168
169 /* returns number of input frames used */
170 static int resample_frames(int16_t *in, size_t num_frames, bool have_more,
171                 struct resample_context *ctx, int16_t **result,
172                 size_t *result_frames)
173 {
174         int ret, num_samples, out_samples;
175         int16_t *out;
176         SRC_DATA data;
177
178         data.src_ratio = ctx->ratio;
179         data.end_of_input = !have_more;
180
181         data.input_frames = num_frames;
182         num_samples = num_frames * ctx->channels;
183         data.output_frames = num_frames * ctx->ratio + 1;
184         out_samples = data.output_frames * ctx->channels;
185
186         data.data_in = para_malloc(num_samples * sizeof(float));
187         src_short_to_float_array(in, data.data_in, num_samples);
188         data.data_out = para_malloc(out_samples * sizeof(float));
189         ret = src_process(ctx->src_state, &data);
190         free(data.data_in);
191         if (ret != 0) {
192                 PARA_ERROR_LOG("%s\n", src_strerror(ret));
193                 free(data.data_out);
194                 return -E_LIBSAMPLERATE;
195         }
196         out_samples = data.output_frames_gen * ctx->channels;
197         out = para_malloc(out_samples * sizeof(short));
198         src_float_to_short_array(data.data_out, out, out_samples);
199         free(data.data_out);
200         *result = out;
201         *result_frames = data.output_frames_gen;
202         return data.input_frames_used;
203 }
204
205 static int resample_post_select(__a_unused struct sched *s, void *context)
206 {
207         int ret;
208         struct filter_node *fn = context;
209         struct resample_context *ctx = fn->private_data;
210         struct resample_filter_args_info *conf = fn->conf;
211         struct btr_node *btrn = fn->btrn;
212         int16_t *in, *out;
213         size_t in_bytes, num_frames;
214         bool have_more;
215
216         ret = check_wav_post_select(ctx->cwc);
217         if (ret < 0)
218                 goto out;
219         if (!ctx->src_state) {
220                 ret = resample_init(fn);
221                 if (ret <= 0)
222                         goto out;
223         }
224         ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
225         if (ret <= 0)
226                 goto out;
227         if (ctx->source_sample_rate == conf->dest_sample_rate_arg) {
228                 /*
229                  * No resampling necessary. We do not splice ourselves out
230                  * though, since our children might want to ask us through the
231                  * btr exec mechanism for the destination samplerate and the
232                  * channel count.
233                  */
234                 btr_pushdown(btrn);
235                 return 0;
236         }
237         btr_merge(btrn, fn->min_iqs);
238         in_bytes = btr_next_buffer(btrn, (char **)&in);
239         ret = -E_RESAMPLE_EOF;
240         num_frames = in_bytes / 2 / ctx->channels;
241         if (num_frames == 0)
242                 goto out;
243         have_more = !btr_no_parent(btrn) ||
244                 btr_next_buffer_omit(btrn, in_bytes, NULL) > 0;
245         ret = resample_frames(in, num_frames, have_more, ctx, &out, &num_frames);
246         if (ret < 0)
247                 goto out;
248         btr_consume(btrn, ret * 2 * ctx->channels);
249         btr_add_output((char *)out, num_frames * 2 * ctx->channels, btrn);
250         return 0;
251 out:
252         if (ret < 0) {
253                 btr_remove_node(&fn->btrn);
254                 /* This releases the check_wav btr node */
255                 check_wav_post_select(ctx->cwc);
256         }
257         return ret;
258 }
259
260 static int resample_parse_config(int argc, char **argv, void **config)
261 {
262         int ret, val, given;
263         struct resample_filter_args_info *conf = para_calloc(sizeof(*conf));
264
265         resample_filter_cmdline_parser(argc, argv, conf);
266
267         /* sanity checks */
268         ret = -ERRNO_TO_PARA_ERROR(EINVAL);
269         val = conf->channels_arg;
270         given = conf->channels_given;
271         if (val < 0 || (val == 0 && given))
272                 goto err;
273         val = conf->sample_rate_arg;
274         given = conf->sample_rate_given;
275         if (val < 0 || (val == 0 && given))
276                 goto err;
277         val = conf->dest_sample_rate_arg;
278         given = conf->dest_sample_rate_given;
279         if (val < 0 || (val == 0 && given))
280                 goto err;
281         *config = conf;
282         return 1;
283 err:
284         free(conf);
285         return ret;
286 }
287
288 static void resample_free_config(void *conf)
289 {
290         if (!conf)
291                 return;
292         resample_filter_cmdline_parser_free(conf);
293         free(conf);
294 }
295
296 /**
297  * The init function of the resample filter.
298  *
299  * \param f Structure to initialize.
300  */
301 void resample_filter_init(struct filter *f)
302 {
303         struct resample_filter_args_info dummy;
304
305         resample_filter_cmdline_parser_init(&dummy);
306         f->close = resample_close;
307         f->open = resample_open;
308         f->pre_select = resample_pre_select;
309         f->post_select = resample_post_select;
310         f->parse_config = resample_parse_config;
311         f->free_config = resample_free_config;
312         f->execute = resample_execute;
313         f->help = (struct ggo_help)DEFINE_GGO_HELP(resample_filter);
314 }