afh: Unify name of init functions.
[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;
130 const uint32_t trafo[] = {
131 [RCT_BEST] = SRC_SINC_BEST_QUALITY,
132 [RCT_MEDIUM] = SRC_SINC_MEDIUM_QUALITY,
133 [RCT_FASTEST] = SRC_SINC_FASTEST,
134 [RCT_ZERO_ORDER_HOLD] = SRC_ZERO_ORDER_HOLD,
135 [RCT_LINEAR] = SRC_LINEAR
136 };
137 struct resample_context *ctx = fn->private_data;
138 const struct lls_option *o_c = FILTER_CMD_OPT(RESAMPLE, CONVERTER);
139 uint32_t converter = U32_OPTVAL(CONVERTER, fn->lpr);
140
141 PARA_INFO_LOG("converter type: %s\n",
142 lls_enum_string_val(converter, o_c));
143 ret = resample_set_params(fn);
144 if (ret < 0)
145 return ret;
146 ctx->src_state = src_new(trafo[converter],
147 U32_OPTVAL(CHANNELS, fn->lpr), &ret);
148 if (!ctx->src_state) {
149 PARA_ERROR_LOG("%s\n", src_strerror(ret));
150 return -E_LIBSAMPLERATE;
151 }
152 fn->min_iqs = 2 * ctx->channels;
153 return 1;
154 }
155
156 /* returns number of input frames used */
157 static int resample_frames(int16_t *in, size_t num_frames, bool have_more,
158 struct resample_context *ctx, int16_t **result,
159 size_t *result_frames)
160 {
161 int ret, num_samples, out_samples;
162 int16_t *out;
163 SRC_DATA data;
164
165 data.src_ratio = ctx->ratio;
166 data.end_of_input = !have_more;
167
168 data.input_frames = num_frames;
169 num_samples = num_frames * ctx->channels;
170 data.output_frames = num_frames * ctx->ratio + 1;
171 out_samples = data.output_frames * ctx->channels;
172
173 data.data_in = para_malloc(num_samples * sizeof(float));
174 src_short_to_float_array(in, data.data_in, num_samples);
175 data.data_out = para_malloc(out_samples * sizeof(float));
176 ret = src_process(ctx->src_state, &data);
177 free(data.data_in);
178 if (ret != 0) {
179 PARA_ERROR_LOG("%s\n", src_strerror(ret));
180 free(data.data_out);
181 return -E_LIBSAMPLERATE;
182 }
183 out_samples = data.output_frames_gen * ctx->channels;
184 out = para_malloc(out_samples * sizeof(short));
185 src_float_to_short_array(data.data_out, out, out_samples);
186 free(data.data_out);
187 *result = out;
188 *result_frames = data.output_frames_gen;
189 return data.input_frames_used;
190 }
191
192 static int resample_post_select(__a_unused struct sched *s, void *context)
193 {
194 int ret;
195 struct filter_node *fn = context;
196 struct resample_context *ctx = fn->private_data;
197 struct btr_node *btrn = fn->btrn;
198 int16_t *in, *out;
199 size_t in_bytes, num_frames;
200 bool have_more;
201
202 ret = check_wav_post_select(ctx->cwc);
203 if (ret < 0)
204 goto out;
205 ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
206 if (ret <= 0)
207 goto out;
208 if (!ctx->src_state) {
209 ret = resample_init(fn);
210 if (ret <= 0)
211 goto out;
212 }
213 if (ctx->source_sample_rate == U32_OPTVAL(DEST_SAMPLE_RATE, fn->lpr)) {
214 /*
215 * No resampling necessary. We do not splice ourselves out
216 * though, since our children might want to ask us through the
217 * btr exec mechanism for the destination samplerate and the
218 * channel count.
219 */
220 btr_pushdown(btrn);
221 return 0;
222 }
223 btr_merge(btrn, fn->min_iqs);
224 in_bytes = btr_next_buffer(btrn, (char **)&in);
225 ret = -E_RESAMPLE_EOF;
226 num_frames = in_bytes / 2 / ctx->channels;
227 if (num_frames == 0)
228 goto out;
229 have_more = !btr_no_parent(btrn) ||
230 btr_next_buffer_omit(btrn, in_bytes, NULL) > 0;
231 ret = resample_frames(in, num_frames, have_more, ctx, &out, &num_frames);
232 if (ret < 0)
233 goto out;
234 btr_consume(btrn, ret * 2 * ctx->channels);
235 btr_add_output((char *)out, num_frames * 2 * ctx->channels, btrn);
236 return 0;
237 out:
238 if (ret < 0) {
239 btr_remove_node(&fn->btrn);
240 /* This releases the check_wav btr node */
241 check_wav_post_select(ctx->cwc);
242 }
243 return ret;
244 }
245
246 static void *resample_setup(const struct lls_parse_result *lpr)
247 {
248 int given;
249 uint32_t u32;
250
251 /* sanity checks */
252 u32 = U32_OPTVAL(CHANNELS, lpr);
253 given = OPT_GIVEN(CHANNELS, lpr);
254 if (u32 == 0 && given) {
255 PARA_EMERG_LOG("fatal: zero channels?!\n");
256 exit(EXIT_FAILURE);
257 }
258 u32 = U32_OPTVAL(SAMPLE_RATE, lpr);
259 given = OPT_GIVEN(SAMPLE_RATE, lpr);
260 if (u32 == 0 && given) {
261 PARA_EMERG_LOG("fatal: input sample rate can not be 0\n");
262 exit(EXIT_FAILURE);
263 }
264 u32 = U32_OPTVAL(DEST_SAMPLE_RATE, lpr);
265 given = OPT_GIVEN(DEST_SAMPLE_RATE, lpr);
266 if (u32 == 0 && given) {
267 PARA_EMERG_LOG("fatal: destination sample rate can not be 0\n");
268 exit(EXIT_FAILURE);
269 }
270 return NULL;
271 }
272
273 static void resample_teardown(__a_unused const struct lls_parse_result *lpr,
274 void *conf)
275 {
276 free(conf);
277 }
278
279 const struct filter lsg_filter_cmd_com_resample_user_data = {
280 .setup = resample_setup,
281 .open = resample_open,
282 .pre_select = resample_pre_select,
283 .post_select = resample_post_select,
284 .close = resample_close,
285 .teardown = resample_teardown,
286 .execute = resample_execute
287 };