2 * Copyright (C) 2012-2013 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file resample_filter.c A sample rate converter based on libsamplerate. */
10 #include <samplerate.h>
12 #include "resample_filter.cmdline.h"
18 #include "buffer_tree.h"
21 #include "check_wav.h"
23 struct resample_context
{
25 int source_sample_rate
;
28 struct check_wav_context
*cwc
;
31 static int resample_execute(struct btr_node
*btrn
, const char *cmd
, char **result
)
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
;
37 return decoder_execute(cmd
, conf
->dest_sample_rate_arg
, ctx
->channels
,
41 static void resample_close(struct filter_node
*fn
)
43 struct resample_context
*ctx
= fn
->private_data
;
47 check_wav_shutdown(ctx
->cwc
);
49 src_delete(ctx
->src_state
);
51 fn
->private_data
= NULL
;
54 static void resample_open(struct filter_node
*fn
)
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
;
61 fn
->private_data
= ctx
;
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
);
68 static void resample_pre_select(struct sched
*s
, struct task
*t
)
70 struct filter_node
*fn
= container_of(t
, struct filter_node
, task
);
71 struct resample_context
*ctx
= fn
->private_data
;
72 int ret
= btr_node_status(fn
->btrn
, fn
->min_iqs
, BTR_NT_INTERNAL
);
75 return sched_min_delay(s
);
76 check_wav_pre_select(s
, ctx
->cwc
);
79 static int get_btr_val(const char *what
, struct btr_node
*btrn
)
83 int ret
= btr_exec_up(btr_parent(btrn
), what
, &buf
);
86 PARA_NOTICE_LOG("btr exec for \"%s\" failed\n", what
);
89 ret
= para_atoi32(buf
, &val
);
91 return ret
< 0? ret
: val
;
94 static int resample_set_params(struct filter_node
*fn
)
97 struct resample_context
*ctx
= fn
->private_data
;
98 struct resample_filter_args_info
*conf
= fn
->conf
;
99 struct btr_node
*btrn
= fn
->btrn
;
101 ctx
->channels
= conf
->channels_arg
;
102 if (!conf
->channels_given
) {
103 ret
= get_btr_val("channels", btrn
);
108 ctx
->source_sample_rate
= conf
->sample_rate_arg
;
109 if (!conf
->sample_rate_given
) {
110 ret
= get_btr_val("sample_rate", btrn
);
112 ctx
->source_sample_rate
= ret
;
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
);
122 ctx
->ratio
= (float)conf
->dest_sample_rate_arg
/ ctx
->source_sample_rate
;
126 static int resample_init(struct filter_node
*fn
)
129 struct resample_context
*ctx
= fn
->private_data
;
130 struct resample_filter_args_info
*conf
= fn
->conf
;
131 struct btr_node
*btrn
= fn
->btrn
;
133 ret
= -E_RESAMPLE_EOF
;
134 if (btr_no_parent(btrn
))
136 if (btr_get_input_queue_size(btrn
) == 0)
138 ret
= resample_set_params(fn
);
141 switch (conf
->converter_arg
) {
142 case converter_arg_best
:
143 converter
= SRC_SINC_BEST_QUALITY
;
145 case converter_arg_medium
:
146 converter
= SRC_SINC_MEDIUM_QUALITY
;
148 case converter_arg_fastest
:
149 converter
= SRC_SINC_FASTEST
;
151 case converter_arg_zero_order_hold
:
152 converter
= SRC_ZERO_ORDER_HOLD
;
154 case converter_arg_linear
:
155 converter
= SRC_LINEAR
;
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
;
165 fn
->min_iqs
= 2 * ctx
->channels
;
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
)
174 int ret
, num_samples
, out_samples
;
178 data
.src_ratio
= ctx
->ratio
;
179 data
.end_of_input
= !have_more
;
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
;
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
);
192 PARA_ERROR_LOG("%s\n", src_strerror(ret
));
194 return -E_LIBSAMPLERATE
;
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
);
201 *result_frames
= data
.output_frames_gen
;
202 return data
.input_frames_used
;
205 static int resample_post_select(__a_unused
struct sched
*s
, struct task
*t
)
208 struct filter_node
*fn
= container_of(t
, struct filter_node
, task
);
209 struct resample_context
*ctx
= fn
->private_data
;
210 struct resample_filter_args_info
*conf
= fn
->conf
;
211 struct btr_node
*btrn
= fn
->btrn
;
213 size_t in_bytes
, num_frames
;
216 ret
= check_wav_post_select(ctx
->cwc
);
219 if (!ctx
->src_state
) {
220 ret
= resample_init(fn
);
224 ret
= btr_node_status(btrn
, fn
->min_iqs
, BTR_NT_INTERNAL
);
227 if (ctx
->source_sample_rate
== conf
->dest_sample_rate_arg
) {
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
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
;
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
);
248 btr_consume(btrn
, ret
* 2 * ctx
->channels
);
249 btr_add_output((char *)out
, num_frames
* 2 * ctx
->channels
, btrn
);
253 btr_remove_node(&fn
->btrn
);
254 /* This releases the check_wav btr node */
255 check_wav_post_select(ctx
->cwc
);
260 static int resample_parse_config(int argc
, char **argv
, void **config
)
263 struct resample_filter_args_info
*conf
= para_calloc(sizeof(*conf
));
265 resample_filter_cmdline_parser(argc
, argv
, conf
);
268 ret
= -ERRNO_TO_PARA_ERROR(EINVAL
);
269 val
= conf
->channels_arg
;
270 given
= conf
->channels_given
;
271 if (val
< 0 || (val
== 0 && given
))
273 val
= conf
->sample_rate_arg
;
274 given
= conf
->sample_rate_given
;
275 if (val
< 0 || (val
== 0 && given
))
277 val
= conf
->dest_sample_rate_arg
;
278 given
= conf
->dest_sample_rate_given
;
279 if (val
< 0 || (val
== 0 && given
))
288 static void resample_free_config(void *conf
)
292 resample_filter_cmdline_parser_free(conf
);
297 * The init function of the resample filter.
299 * \param f Structure to initialize.
301 void resample_filter_init(struct filter
*f
)
303 struct resample_filter_args_info dummy
;
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
);