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