1 /*
2 * Rate converter plugin using libavresample
3 * Copyright (c) 2014 by Anton Khirnov
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 */
15
16 #include <stdio.h>
17 #include <alsa/asoundlib.h>
18 #include <alsa/pcm_rate.h>
19
20 #include <libavresample/avresample.h>
21 #include <libavutil/channel_layout.h>
22 #include <libavutil/opt.h>
23 #include <libavutil/mathematics.h>
24 #include <libavutil/samplefmt.h>
25
26
27 static unsigned int filter_size = 16;
28 static unsigned int phase_shift = 10; /* auto-adjusts */
29 static double cutoff = 0; /* auto-adjusts */
30
31 struct rate_src {
32 AVAudioResampleContext *avr;
33
34 unsigned int in_rate;
35 unsigned int out_rate;
36 unsigned int channels;
37 };
38
input_frames(void * obj ATTRIBUTE_UNUSED,snd_pcm_uframes_t frames)39 static snd_pcm_uframes_t input_frames(void *obj ATTRIBUTE_UNUSED,
40 snd_pcm_uframes_t frames)
41 {
42 return frames;
43 }
44
output_frames(void * obj ATTRIBUTE_UNUSED,snd_pcm_uframes_t frames)45 static snd_pcm_uframes_t output_frames(void *obj ATTRIBUTE_UNUSED,
46 snd_pcm_uframes_t frames)
47 {
48 return frames;
49 }
50
pcm_src_free(void * obj)51 static void pcm_src_free(void *obj)
52 {
53 struct rate_src *rate = obj;
54 avresample_free(&rate->avr);
55 }
56
pcm_src_init(void * obj,snd_pcm_rate_info_t * info)57 static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info)
58 {
59 struct rate_src *rate = obj;
60 int i, ir, or;
61
62 if (!rate->avr || rate->channels != info->channels) {
63 int ret;
64
65 pcm_src_free(rate);
66 rate->channels = info->channels;
67 ir = rate->in_rate = info->in.rate;
68 or = rate->out_rate = info->out.rate;
69 i = av_gcd(or, ir);
70 if (or > ir) {
71 phase_shift = or/i;
72 } else {
73 phase_shift = ir/i;
74 }
75 if (cutoff <= 0.0) {
76 cutoff = 1.0 - 1.0/filter_size;
77 if (cutoff < 0.80)
78 cutoff = 0.80;
79 }
80
81 rate->avr = avresample_alloc_context();
82 if (!rate->avr)
83 return -ENOMEM;
84
85 av_opt_set_int(rate->avr, "in_sample_rate", info->in.rate, 0);
86 av_opt_set_int(rate->avr, "out_sample_rate", info->out.rate, 0);
87 av_opt_set_int(rate->avr, "in_sample_format", AV_SAMPLE_FMT_S16, 0);
88 av_opt_set_int(rate->avr, "out_sample_format", AV_SAMPLE_FMT_S16, 0);
89 av_opt_set_int(rate->avr, "in_channel_layout", av_get_default_channel_layout(rate->channels), 0);
90 av_opt_set_int(rate->avr, "out_channel_layout", av_get_default_channel_layout(rate->channels), 0);
91
92 av_opt_set_int(rate->avr, "filter_size", filter_size, 0);
93 av_opt_set_int(rate->avr, "phase_shift", phase_shift, 0);
94 av_opt_set_double(rate->avr, "cutoff", cutoff, 0);
95
96 ret = avresample_open(rate->avr);
97 if (ret < 0) {
98 avresample_free(&rate->avr);
99 return -EINVAL;
100 }
101 }
102
103 return 0;
104 }
105
pcm_src_adjust_pitch(void * obj,snd_pcm_rate_info_t * info)106 static int pcm_src_adjust_pitch(void *obj, snd_pcm_rate_info_t *info)
107 {
108 struct rate_src *rate = obj;
109
110 if (info->out.rate != rate->out_rate || info->in.rate != rate->in_rate)
111 pcm_src_init(obj, info);
112 return 0;
113 }
114
pcm_src_reset(void * obj)115 static void pcm_src_reset(void *obj)
116 {
117 struct rate_src *rate = obj;
118
119 if (rate->avr) {
120 #if 0
121 avresample_close(rate->avr);
122 avresample_open(rate->avr);
123 #endif
124 }
125 }
126
pcm_src_convert_s16(void * obj,int16_t * dst,unsigned int dst_frames,const int16_t * src,unsigned int src_frames)127 static void pcm_src_convert_s16(void *obj, int16_t *dst,
128 unsigned int dst_frames,
129 const int16_t *src,
130 unsigned int src_frames)
131 {
132 struct rate_src *rate = obj;
133 int chans = rate->channels;
134 unsigned int total_in = avresample_get_delay(rate->avr) + src_frames;
135
136 avresample_convert(rate->avr, (uint8_t **)&dst, dst_frames * chans * 2, dst_frames,
137 (uint8_t **)&src, src_frames * chans * 2, src_frames);
138
139 avresample_set_compensation(rate->avr,
140 total_in - src_frames > filter_size ? 0 : 1, src_frames);
141 }
142
pcm_src_close(void * obj)143 static void pcm_src_close(void *obj)
144 {
145 pcm_src_free(obj);
146 }
147
148 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
get_supported_rates(void * obj ATTRIBUTE_UNUSED,unsigned int * rate_min,unsigned int * rate_max)149 static int get_supported_rates(void *obj ATTRIBUTE_UNUSED,
150 unsigned int *rate_min,
151 unsigned int *rate_max)
152 {
153 *rate_min = *rate_max = 0; /* both unlimited */
154 return 0;
155 }
156
dump(void * obj ATTRIBUTE_UNUSED,snd_output_t * out)157 static void dump(void *obj ATTRIBUTE_UNUSED, snd_output_t *out)
158 {
159 snd_output_printf(out, "Converter: libavr\n");
160 }
161 #endif
162
163 static snd_pcm_rate_ops_t pcm_src_ops = {
164 .close = pcm_src_close,
165 .init = pcm_src_init,
166 .free = pcm_src_free,
167 .reset = pcm_src_reset,
168 .adjust_pitch = pcm_src_adjust_pitch,
169 .convert_s16 = pcm_src_convert_s16,
170 .input_frames = input_frames,
171 .output_frames = output_frames,
172 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
173 .version = SND_PCM_RATE_PLUGIN_VERSION,
174 .get_supported_rates = get_supported_rates,
175 .dump = dump,
176 #endif
177 };
178
pcm_src_open(unsigned int version,void ** objp,snd_pcm_rate_ops_t * ops)179 int pcm_src_open(unsigned int version, void **objp, snd_pcm_rate_ops_t *ops)
180
181 {
182 struct rate_src *rate;
183
184 #if SND_PCM_RATE_PLUGIN_VERSION < 0x010002
185 if (version != SND_PCM_RATE_PLUGIN_VERSION) {
186 fprintf(stderr, "Invalid rate plugin version %x\n", version);
187 return -EINVAL;
188 }
189 #endif
190 rate = calloc(1, sizeof(*rate));
191 if (!rate)
192 return -ENOMEM;
193
194 *objp = rate;
195 rate->avr = NULL;
196 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
197 if (version == 0x010001)
198 memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t));
199 else
200 #endif
201 *ops = pcm_src_ops;
202 return 0;
203 }
204
SND_PCM_RATE_PLUGIN_ENTRY(lavrate)205 int SND_PCM_RATE_PLUGIN_ENTRY(lavrate)(unsigned int version, void **objp,
206 snd_pcm_rate_ops_t *ops)
207 {
208 return pcm_src_open(version, objp, ops);
209 }
SND_PCM_RATE_PLUGIN_ENTRY(lavrate_higher)210 int SND_PCM_RATE_PLUGIN_ENTRY(lavrate_higher)(unsigned int version,
211 void **objp, snd_pcm_rate_ops_t *ops)
212 {
213 filter_size = 64;
214 return pcm_src_open(version, objp, ops);
215 }
SND_PCM_RATE_PLUGIN_ENTRY(lavrate_high)216 int SND_PCM_RATE_PLUGIN_ENTRY(lavrate_high)(unsigned int version,
217 void **objp, snd_pcm_rate_ops_t *ops)
218 {
219 filter_size = 32;
220 return pcm_src_open(version, objp, ops);
221 }
SND_PCM_RATE_PLUGIN_ENTRY(lavrate_fast)222 int SND_PCM_RATE_PLUGIN_ENTRY(lavrate_fast)(unsigned int version,
223 void **objp, snd_pcm_rate_ops_t *ops)
224 {
225 filter_size = 8;
226 return pcm_src_open(version, objp, ops);
227 }
SND_PCM_RATE_PLUGIN_ENTRY(lavrate_faster)228 int SND_PCM_RATE_PLUGIN_ENTRY(lavrate_faster)(unsigned int version,
229 void **objp, snd_pcm_rate_ops_t *ops)
230 {
231 filter_size = 4;
232 return pcm_src_open(version, objp, ops);
233 }
234
235
236