]> git.tuebingen.mpg.de Git - paraslash.git/blob - resample_filter.c
Convert filters to lopsub.
[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 #include <lopsub.h>
12
13 #include "filter_cmd.lsg.h"
14 #include "para.h"
15 #include "error.h"
16 #include "list.h"
17 #include "sched.h"
18 #include "buffer_tree.h"
19 #include "filter.h"
20 #include "string.h"
21 #include "check_wav.h"
22
23 #define U32_OPTVAL(_opt, _lpr) (FILTER_CMD_OPT_UINT32_VAL(RESAMPLE, _opt, _lpr))
24 #define OPT_GIVEN(_opt, _lpr) (FILTER_CMD_OPT_GIVEN(RESAMPLE, _opt, _lpr))
25
26 /* effective values, may differ from config arg */
27 struct resample_context {
28         uint32_t channels;
29         int source_sample_rate;
30         float ratio;
31         SRC_STATE *src_state;
32         struct check_wav_context *cwc;
33 };
34
35 static int resample_execute(struct btr_node *btrn, const char *cmd, char **result)
36 {
37         struct filter_node *fn = btr_context(btrn);
38         struct resample_context *ctx = fn->private_data;
39         uint32_t dsr = U32_OPTVAL(DEST_SAMPLE_RATE, fn->lpr);
40         return decoder_execute(cmd, dsr, ctx->channels, result);
41 }
42
43 static void resample_close(struct filter_node *fn)
44 {
45         struct resample_context *ctx = fn->private_data;
46
47         if (!ctx)
48                 return;
49         check_wav_shutdown(ctx->cwc);
50         if (ctx->src_state)
51                 src_delete(ctx->src_state);
52         free(ctx);
53         fn->private_data = NULL;
54 }
55
56 static void resample_open(struct filter_node *fn)
57 {
58         struct resample_context *ctx = para_calloc(sizeof(*ctx));
59         struct btr_node *btrn = fn->btrn;
60         struct wav_params wp;
61
62         fn->private_data = ctx;
63         fn->min_iqs = 2;
64         LLS_COPY_WAV_PARMS(&wp, LSG_FILTER_CMD_RESAMPLE, fn->lpr);
65         ctx->cwc = check_wav_init(btr_parent(btrn), btrn, &wp, NULL);
66         btr_log_tree(btr_parent(btr_parent(btrn)), LL_INFO);
67 }
68
69 static void resample_pre_select(struct sched *s, void *context)
70 {
71         struct filter_node *fn = context;
72         struct resample_context *ctx = fn->private_data;
73         int ret = btr_node_status(fn->btrn, fn->min_iqs, BTR_NT_INTERNAL);
74
75         if (ret != 0)
76                 return sched_min_delay(s);
77         check_wav_pre_select(s, ctx->cwc);
78 }
79
80 static int get_btr_val(const char *what, struct btr_node *btrn)
81 {
82         char *buf;
83         int32_t val;
84         int ret = btr_exec_up(btr_parent(btrn), what, &buf);
85
86         if (ret < 0) {
87                 PARA_NOTICE_LOG("btr exec for \"%s\" failed\n", what);
88                 return ret;
89         }
90         ret = para_atoi32(buf, &val);
91         free(buf);
92         return ret < 0? ret : val;
93 }
94
95 static int resample_set_params(struct filter_node *fn)
96 {
97         int ret;
98         struct resample_context *ctx = fn->private_data;
99         struct btr_node *btrn = fn->btrn;
100         struct lls_parse_result *lpr = fn->lpr;
101
102         ctx->channels = U32_OPTVAL(CHANNELS, lpr);
103         if (!OPT_GIVEN(CHANNELS, lpr)) {
104                 ret = get_btr_val("channels", btrn);
105                 if (ret >= 0)
106                         ctx->channels = ret;
107         }
108         ctx->source_sample_rate = U32_OPTVAL(SAMPLE_RATE, lpr);
109         if (!OPT_GIVEN(SAMPLE_RATE, lpr)) {
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 * const 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 = U32_OPTVAL(DEST_SAMPLE_RATE, lpr)
123                 / (float)ctx->source_sample_rate;
124         return 1;
125 }
126
127 static int resample_init(struct filter_node *fn)
128 {
129         int ret, converter = *(int *)fn->conf;
130         struct resample_context *ctx = fn->private_data;
131
132         ret = resample_set_params(fn);
133         if (ret < 0)
134                 return ret;
135         ctx->src_state = src_new(converter, U32_OPTVAL(CHANNELS, fn->lpr), &ret);
136         if (!ctx->src_state) {
137                 PARA_ERROR_LOG("%s\n", src_strerror(ret));
138                 return -E_LIBSAMPLERATE;
139         }
140         fn->min_iqs = 2 * ctx->channels;
141         return 1;
142 }
143
144 /* returns number of input frames used */
145 static int resample_frames(int16_t *in, size_t num_frames, bool have_more,
146                 struct resample_context *ctx, int16_t **result,
147                 size_t *result_frames)
148 {
149         int ret, num_samples, out_samples;
150         int16_t *out;
151         SRC_DATA data;
152
153         data.src_ratio = ctx->ratio;
154         data.end_of_input = !have_more;
155
156         data.input_frames = num_frames;
157         num_samples = num_frames * ctx->channels;
158         data.output_frames = num_frames * ctx->ratio + 1;
159         out_samples = data.output_frames * ctx->channels;
160
161         data.data_in = para_malloc(num_samples * sizeof(float));
162         src_short_to_float_array(in, data.data_in, num_samples);
163         data.data_out = para_malloc(out_samples * sizeof(float));
164         ret = src_process(ctx->src_state, &data);
165         free(data.data_in);
166         if (ret != 0) {
167                 PARA_ERROR_LOG("%s\n", src_strerror(ret));
168                 free(data.data_out);
169                 return -E_LIBSAMPLERATE;
170         }
171         out_samples = data.output_frames_gen * ctx->channels;
172         out = para_malloc(out_samples * sizeof(short));
173         src_float_to_short_array(data.data_out, out, out_samples);
174         free(data.data_out);
175         *result = out;
176         *result_frames = data.output_frames_gen;
177         return data.input_frames_used;
178 }
179
180 static int resample_post_select(__a_unused struct sched *s, void *context)
181 {
182         int ret;
183         struct filter_node *fn = context;
184         struct resample_context *ctx = fn->private_data;
185         struct btr_node *btrn = fn->btrn;
186         int16_t *in, *out;
187         size_t in_bytes, num_frames;
188         bool have_more;
189
190         ret = check_wav_post_select(ctx->cwc);
191         if (ret < 0)
192                 goto out;
193         ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
194         if (ret <= 0)
195                 goto out;
196         if (!ctx->src_state) {
197                 ret = resample_init(fn);
198                 if (ret <= 0)
199                         goto out;
200         }
201         if (ctx->source_sample_rate == U32_OPTVAL(DEST_SAMPLE_RATE, fn->lpr)) {
202                 /*
203                  * No resampling necessary. We do not splice ourselves out
204                  * though, since our children might want to ask us through the
205                  * btr exec mechanism for the destination samplerate and the
206                  * channel count.
207                  */
208                 btr_pushdown(btrn);
209                 return 0;
210         }
211         btr_merge(btrn, fn->min_iqs);
212         in_bytes = btr_next_buffer(btrn, (char **)&in);
213         ret = -E_RESAMPLE_EOF;
214         num_frames = in_bytes / 2 / ctx->channels;
215         if (num_frames == 0)
216                 goto out;
217         have_more = !btr_no_parent(btrn) ||
218                 btr_next_buffer_omit(btrn, in_bytes, NULL) > 0;
219         ret = resample_frames(in, num_frames, have_more, ctx, &out, &num_frames);
220         if (ret < 0)
221                 goto out;
222         btr_consume(btrn, ret * 2 * ctx->channels);
223         btr_add_output((char *)out, num_frames * 2 * ctx->channels, btrn);
224         return 0;
225 out:
226         if (ret < 0) {
227                 btr_remove_node(&fn->btrn);
228                 /* This releases the check_wav btr node */
229                 check_wav_post_select(ctx->cwc);
230         }
231         return ret;
232 }
233
234 static void *resample_setup(const struct lls_parse_result *lpr)
235 {
236         int given, *converter;
237         const char *converter_arg;
238         uint32_t u32;
239
240         /* sanity checks */
241         u32 = U32_OPTVAL(CHANNELS, lpr);
242         given = OPT_GIVEN(CHANNELS, lpr);
243         if (u32 == 0 && given) {
244                 PARA_EMERG_LOG("fatal: zero channels?!\n");
245                 exit(EXIT_FAILURE);
246         }
247         u32 = U32_OPTVAL(SAMPLE_RATE, lpr);
248         given = OPT_GIVEN(SAMPLE_RATE, lpr);
249         if (u32 == 0 && given) {
250                 PARA_EMERG_LOG("fatal: input sample rate can not be 0\n");
251                 exit(EXIT_FAILURE);
252         }
253         u32 = U32_OPTVAL(DEST_SAMPLE_RATE, lpr);
254         given = OPT_GIVEN(DEST_SAMPLE_RATE, lpr);
255         if (u32 == 0 && given) {
256                 PARA_EMERG_LOG("fatal: destination sample rate can not be 0\n");
257                 exit(EXIT_FAILURE);
258         }
259         converter = para_malloc(sizeof(int));
260         converter_arg = FILTER_CMD_OPT_STRING_VAL(RESAMPLE, CONVERTER, lpr);
261         if (!strcmp(converter_arg, "best"))
262                 *converter = SRC_SINC_BEST_QUALITY;
263         else if (!strcmp(converter_arg, "medium"))
264                 *converter = SRC_SINC_MEDIUM_QUALITY;
265         else if (!strcmp(converter_arg, "fastest"))
266                 *converter = SRC_SINC_FASTEST;
267         else if (!strcmp(converter_arg, "zero_order_hold"))
268                 *converter = SRC_ZERO_ORDER_HOLD;
269         else if (!strcmp(converter_arg, "linear"))
270                 *converter = SRC_LINEAR;
271         else {
272                 PARA_EMERG_LOG("invalid converter type: %s\n", converter_arg);
273                 exit(EXIT_FAILURE);
274         }
275         return converter;
276 }
277
278 static void resample_teardown(__a_unused const struct lls_parse_result *lpr,
279                 void *conf)
280 {
281         free(conf);
282 }
283
284 const struct filter lsg_filter_cmd_com_resample_user_data = {
285         .setup = resample_setup,
286         .open = resample_open,
287         .pre_select = resample_pre_select,
288         .post_select = resample_post_select,
289         .close = resample_close,
290         .teardown = resample_teardown,
291         .execute = resample_execute
292 };