server: Fix return value of com_ff().
[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
132 ret = resample_set_params(fn);
133 if (ret < 0)
134 return ret;
135 switch (conf->converter_arg) {
136 case converter_arg_best:
137 converter = SRC_SINC_BEST_QUALITY;
138 break;
139 case converter_arg_medium:
140 converter = SRC_SINC_MEDIUM_QUALITY;
141 break;
142 case converter_arg_fastest:
143 converter = SRC_SINC_FASTEST;
144 break;
145 case converter_arg_zero_order_hold:
146 converter = SRC_ZERO_ORDER_HOLD;
147 break;
148 case converter_arg_linear:
149 converter = SRC_LINEAR;
150 break;
151 default:
152 assert(0);
153 }
154 ctx->src_state = src_new(converter, conf->channels_arg, &ret);
155 if (!ctx->src_state) {
156 PARA_ERROR_LOG("%s\n", src_strerror(ret));
157 return -E_LIBSAMPLERATE;
158 }
159 fn->min_iqs = 2 * ctx->channels;
160 return 1;
161 }
162
163 /* returns number of input frames used */
164 static int resample_frames(int16_t *in, size_t num_frames, bool have_more,
165 struct resample_context *ctx, int16_t **result,
166 size_t *result_frames)
167 {
168 int ret, num_samples, out_samples;
169 float *in_float;
170 int16_t *out;
171 SRC_DATA data;
172
173 data.src_ratio = ctx->ratio;
174 data.end_of_input = !have_more;
175
176 data.input_frames = num_frames;
177 num_samples = num_frames * ctx->channels;
178 data.output_frames = num_frames * ctx->ratio + 1;
179 out_samples = data.output_frames * ctx->channels;
180
181 in_float = para_malloc(num_samples * sizeof(float));
182 src_short_to_float_array(in, in_float, num_samples);
183 data.data_in = in_float;
184 data.data_out = para_malloc(out_samples * sizeof(float));
185 ret = src_process(ctx->src_state, &data);
186 free(in_float);
187 if (ret != 0) {
188 PARA_ERROR_LOG("%s\n", src_strerror(ret));
189 free(data.data_out);
190 return -E_LIBSAMPLERATE;
191 }
192 out_samples = data.output_frames_gen * ctx->channels;
193 out = para_malloc(out_samples * sizeof(short));
194 src_float_to_short_array(data.data_out, out, out_samples);
195 free(data.data_out);
196 *result = out;
197 *result_frames = data.output_frames_gen;
198 return data.input_frames_used;
199 }
200
201 static int resample_post_select(__a_unused struct sched *s, void *context)
202 {
203 int ret;
204 struct filter_node *fn = context;
205 struct resample_context *ctx = fn->private_data;
206 struct resample_filter_args_info *conf = fn->conf;
207 struct btr_node *btrn = fn->btrn;
208 int16_t *in, *out;
209 size_t in_bytes, num_frames;
210 bool have_more;
211
212 ret = check_wav_post_select(ctx->cwc);
213 if (ret < 0)
214 goto out;
215 ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
216 if (ret <= 0)
217 goto out;
218 if (!ctx->src_state) {
219 ret = resample_init(fn);
220 if (ret <= 0)
221 goto out;
222 }
223 if (ctx->source_sample_rate == conf->dest_sample_rate_arg) {
224 /*
225 * No resampling necessary. We do not splice ourselves out
226 * though, since our children might want to ask us through the
227 * btr exec mechanism for the destination samplerate and the
228 * channel count.
229 */
230 btr_pushdown(btrn);
231 return 0;
232 }
233 btr_merge(btrn, fn->min_iqs);
234 in_bytes = btr_next_buffer(btrn, (char **)&in);
235 ret = -E_RESAMPLE_EOF;
236 num_frames = in_bytes / 2 / ctx->channels;
237 if (num_frames == 0)
238 goto out;
239 have_more = !btr_no_parent(btrn) ||
240 btr_next_buffer_omit(btrn, in_bytes, NULL) > 0;
241 ret = resample_frames(in, num_frames, have_more, ctx, &out, &num_frames);
242 if (ret < 0)
243 goto out;
244 btr_consume(btrn, ret * 2 * ctx->channels);
245 btr_add_output((char *)out, num_frames * 2 * ctx->channels, btrn);
246 return 0;
247 out:
248 if (ret < 0) {
249 btr_remove_node(&fn->btrn);
250 /* This releases the check_wav btr node */
251 check_wav_post_select(ctx->cwc);
252 }
253 return ret;
254 }
255
256 static int resample_parse_config(int argc, char **argv, void **config)
257 {
258 int ret, val, given;
259 struct resample_filter_args_info *conf = para_calloc(sizeof(*conf));
260
261 resample_filter_cmdline_parser(argc, argv, conf);
262
263 /* sanity checks */
264 ret = -ERRNO_TO_PARA_ERROR(EINVAL);
265 val = conf->channels_arg;
266 given = conf->channels_given;
267 if (val < 0 || (val == 0 && given))
268 goto err;
269 val = conf->sample_rate_arg;
270 given = conf->sample_rate_given;
271 if (val < 0 || (val == 0 && given))
272 goto err;
273 val = conf->dest_sample_rate_arg;
274 given = conf->dest_sample_rate_given;
275 if (val < 0 || (val == 0 && given))
276 goto err;
277 *config = conf;
278 return 1;
279 err:
280 free(conf);
281 return ret;
282 }
283
284 static void resample_free_config(void *conf)
285 {
286 if (!conf)
287 return;
288 resample_filter_cmdline_parser_free(conf);
289 free(conf);
290 }
291
292 /**
293 * The init function of the resample filter.
294 *
295 * \param f Structure to initialize.
296 */
297 void resample_filter_init(struct filter *f)
298 {
299 struct resample_filter_args_info dummy;
300
301 resample_filter_cmdline_parser_init(&dummy);
302 f->close = resample_close;
303 f->open = resample_open;
304 f->pre_select = resample_pre_select;
305 f->post_select = resample_post_select;
306 f->parse_config = resample_parse_config;
307 f->free_config = resample_free_config;
308 f->execute = resample_execute;
309 f->help = (struct ggo_help)DEFINE_GGO_HELP(resample_filter);
310 }