Lines 1-291
Link Here
|
1 |
/* |
|
|
2 |
* Rate converter plugin using libavcodec's resampler |
3 |
* Copyright (c) 2007 by Nicholas Kain <njkain@gmail.com> |
4 |
* |
5 |
* based on rate converter that uses libsamplerate |
6 |
* Copyright (c) 2006 by Takashi Iwai <tiwai@suse.de> |
7 |
* |
8 |
* This library is free software; you can redistribute it and/or |
9 |
* modify it under the terms of the GNU Lesser General Public |
10 |
* License as published by the Free Software Foundation; either |
11 |
* version 2.1 of the License, or (at your option) any later version. |
12 |
* |
13 |
* This library is distributed in the hope that it will be useful, |
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 |
* Lesser General Public License for more details. |
17 |
*/ |
18 |
|
19 |
#include <stdio.h> |
20 |
#include <alsa/asoundlib.h> |
21 |
#include <alsa/pcm_rate.h> |
22 |
#include AVCODEC_HEADER |
23 |
#include "gcd.h" |
24 |
|
25 |
static int filter_size = 16; |
26 |
static int phase_shift = 10; /* auto-adjusts */ |
27 |
static double cutoff = 0; /* auto-adjusts */ |
28 |
|
29 |
struct rate_src { |
30 |
struct AVResampleContext *context; |
31 |
int in_rate; |
32 |
int out_rate; |
33 |
int stored; |
34 |
int point; |
35 |
int16_t **out; |
36 |
int16_t **in; |
37 |
unsigned int channels; |
38 |
}; |
39 |
|
40 |
static snd_pcm_uframes_t input_frames(void *obj, snd_pcm_uframes_t frames) |
41 |
{ |
42 |
return frames; |
43 |
} |
44 |
|
45 |
static snd_pcm_uframes_t output_frames(void *obj, snd_pcm_uframes_t frames) |
46 |
{ |
47 |
return frames; |
48 |
} |
49 |
|
50 |
static void pcm_src_free(void *obj) |
51 |
{ |
52 |
struct rate_src *rate = obj; |
53 |
int i; |
54 |
|
55 |
if (rate->out) { |
56 |
for (i=0; i<rate->channels; i++) { |
57 |
free(rate->out[i]); |
58 |
} |
59 |
free(rate->out); |
60 |
} |
61 |
if (rate->in) { |
62 |
for (i=0; i<rate->channels; i++) { |
63 |
free(rate->in[i]); |
64 |
} |
65 |
free(rate->in); |
66 |
} |
67 |
rate->out = rate->in = NULL; |
68 |
|
69 |
if (rate->context) { |
70 |
av_resample_close(rate->context); |
71 |
rate->context = NULL; |
72 |
} |
73 |
} |
74 |
|
75 |
static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info) |
76 |
{ |
77 |
struct rate_src *rate = obj; |
78 |
int i, ir, or; |
79 |
|
80 |
if (! rate->context || rate->channels != info->channels) { |
81 |
pcm_src_free(rate); |
82 |
rate->channels = info->channels; |
83 |
ir = rate->in_rate = info->in.rate; |
84 |
or = rate->out_rate = info->out.rate; |
85 |
i = gcd(or, ir); |
86 |
if (or > ir) { |
87 |
phase_shift = or/i; |
88 |
} else { |
89 |
phase_shift = ir/i; |
90 |
} |
91 |
if (cutoff <= 0.0) { |
92 |
cutoff = 1.0 - 1.0/filter_size; |
93 |
if (cutoff < 0.80) |
94 |
cutoff = 0.80; |
95 |
} |
96 |
rate->context = av_resample_init(info->out.rate, info->in.rate, |
97 |
filter_size, phase_shift, |
98 |
(info->out.rate >= info->in.rate ? 0 : 1), cutoff); |
99 |
if (!rate->context) |
100 |
return -EINVAL; |
101 |
} |
102 |
|
103 |
rate->out = malloc(rate->channels * sizeof(int16_t *)); |
104 |
rate->in = malloc(rate->channels * sizeof(int16_t *)); |
105 |
for (i=0; i<rate->channels; i++) { |
106 |
rate->out[i] = calloc(info->out.period_size * 2, |
107 |
sizeof(int16_t)); |
108 |
rate->in[i] = calloc(info->in.period_size * 2, |
109 |
sizeof(int16_t)); |
110 |
} |
111 |
rate->point = info->in.period_size / 2; |
112 |
if (!rate->out || !rate->in) { |
113 |
pcm_src_free(rate); |
114 |
return -ENOMEM; |
115 |
} |
116 |
|
117 |
return 0; |
118 |
} |
119 |
|
120 |
static int pcm_src_adjust_pitch(void *obj, snd_pcm_rate_info_t *info) |
121 |
{ |
122 |
struct rate_src *rate = obj; |
123 |
|
124 |
if (info->out.rate != rate->out_rate || info->in.rate != rate->in_rate) |
125 |
pcm_src_init(obj, info); |
126 |
return 0; |
127 |
} |
128 |
|
129 |
static void pcm_src_reset(void *obj) |
130 |
{ |
131 |
struct rate_src *rate = obj; |
132 |
rate->stored = 0; |
133 |
} |
134 |
|
135 |
static void deinterleave(const int16_t *src, int16_t **dst, unsigned int frames, |
136 |
unsigned int chans, int overflow) |
137 |
{ |
138 |
int i, j; |
139 |
|
140 |
if (chans == 1) { |
141 |
memcpy(dst + overflow, src, frames*sizeof(int16_t)); |
142 |
} else if (chans == 2) { |
143 |
for (j=overflow; j<(frames + overflow); j++) { |
144 |
dst[0][j] = *(src++); |
145 |
dst[1][j] = *(src++); |
146 |
} |
147 |
} else { |
148 |
for (j=overflow; j<(frames + overflow); j++) { |
149 |
for (i=0; i<chans; i++) { |
150 |
dst[i][j] = *(src++); |
151 |
} |
152 |
} |
153 |
} |
154 |
} |
155 |
|
156 |
static void reinterleave(int16_t **src, int16_t *dst, unsigned int frames, |
157 |
unsigned int chans) |
158 |
{ |
159 |
int i, j; |
160 |
|
161 |
if (chans == 1) { |
162 |
memcpy(dst, src, frames*sizeof(int16_t)); |
163 |
} else if (chans == 2) { |
164 |
for (j=0; j<frames; j++) { |
165 |
*(dst++) = src[0][j]; |
166 |
*(dst++) = src[1][j]; |
167 |
} |
168 |
} else { |
169 |
for (j=0; j<frames; j++) { |
170 |
for (i=0; i<chans; i++) { |
171 |
*(dst++) = src[i][j]; |
172 |
} |
173 |
} |
174 |
} |
175 |
} |
176 |
|
177 |
static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int |
178 |
dst_frames, const int16_t *src, unsigned int src_frames) |
179 |
{ |
180 |
struct rate_src *rate = obj; |
181 |
int consumed = 0, chans=rate->channels, ret=0, i; |
182 |
int total_in = rate->stored + src_frames, new_stored; |
183 |
|
184 |
deinterleave(src, rate->in, src_frames, chans, rate->point); |
185 |
for (i=0; i<chans; ++i) { |
186 |
ret = av_resample(rate->context, rate->out[i], |
187 |
rate->in[i]+rate->point-rate->stored, &consumed, |
188 |
total_in, dst_frames, i == (chans - 1)); |
189 |
new_stored = total_in-consumed; |
190 |
memmove(rate->in[i]+rate->point-new_stored, |
191 |
rate->in[i]+rate->point-rate->stored+consumed, |
192 |
new_stored*sizeof(int16_t)); |
193 |
} |
194 |
av_resample_compensate(rate->context, |
195 |
total_in-src_frames>filter_size?0:1, src_frames); |
196 |
reinterleave(rate->out, dst, ret, chans); |
197 |
rate->stored = total_in-consumed; |
198 |
} |
199 |
|
200 |
static void pcm_src_close(void *obj) |
201 |
{ |
202 |
pcm_src_free(obj); |
203 |
} |
204 |
|
205 |
#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 |
206 |
static int get_supported_rates(void *obj, unsigned int *rate_min, |
207 |
unsigned int *rate_max) |
208 |
{ |
209 |
*rate_min = *rate_max = 0; /* both unlimited */ |
210 |
return 0; |
211 |
} |
212 |
|
213 |
static void dump(void *obj, snd_output_t *out) |
214 |
{ |
215 |
snd_output_printf(out, "Converter: liblavc\n"); |
216 |
} |
217 |
#endif |
218 |
|
219 |
static snd_pcm_rate_ops_t pcm_src_ops = { |
220 |
.close = pcm_src_close, |
221 |
.init = pcm_src_init, |
222 |
.free = pcm_src_free, |
223 |
.reset = pcm_src_reset, |
224 |
.adjust_pitch = pcm_src_adjust_pitch, |
225 |
.convert_s16 = pcm_src_convert_s16, |
226 |
.input_frames = input_frames, |
227 |
.output_frames = output_frames, |
228 |
#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 |
229 |
.version = SND_PCM_RATE_PLUGIN_VERSION, |
230 |
.get_supported_rates = get_supported_rates, |
231 |
.dump = dump, |
232 |
#endif |
233 |
}; |
234 |
|
235 |
int pcm_src_open(unsigned int version, void **objp, snd_pcm_rate_ops_t *ops) |
236 |
|
237 |
{ |
238 |
struct rate_src *rate; |
239 |
|
240 |
#if SND_PCM_RATE_PLUGIN_VERSION < 0x010002 |
241 |
if (version != SND_PCM_RATE_PLUGIN_VERSION) { |
242 |
fprintf(stderr, "Invalid rate plugin version %x\n", version); |
243 |
return -EINVAL; |
244 |
} |
245 |
#endif |
246 |
rate = calloc(1, sizeof(*rate)); |
247 |
if (!rate) |
248 |
return -ENOMEM; |
249 |
|
250 |
*objp = rate; |
251 |
rate->context = NULL; |
252 |
#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 |
253 |
if (version == 0x010001) |
254 |
memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t)); |
255 |
else |
256 |
#endif |
257 |
*ops = pcm_src_ops; |
258 |
return 0; |
259 |
} |
260 |
|
261 |
int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate)(unsigned int version, void **objp, |
262 |
snd_pcm_rate_ops_t *ops) |
263 |
{ |
264 |
return pcm_src_open(version, objp, ops); |
265 |
} |
266 |
int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate_higher)(unsigned int version, |
267 |
void **objp, snd_pcm_rate_ops_t *ops) |
268 |
{ |
269 |
filter_size = 64; |
270 |
return pcm_src_open(version, objp, ops); |
271 |
} |
272 |
int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate_high)(unsigned int version, |
273 |
void **objp, snd_pcm_rate_ops_t *ops) |
274 |
{ |
275 |
filter_size = 32; |
276 |
return pcm_src_open(version, objp, ops); |
277 |
} |
278 |
int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate_fast)(unsigned int version, |
279 |
void **objp, snd_pcm_rate_ops_t *ops) |
280 |
{ |
281 |
filter_size = 8; |
282 |
return pcm_src_open(version, objp, ops); |
283 |
} |
284 |
int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate_faster)(unsigned int version, |
285 |
void **objp, snd_pcm_rate_ops_t *ops) |
286 |
{ |
287 |
filter_size = 4; |
288 |
return pcm_src_open(version, objp, ops); |
289 |
} |
290 |
|
291 |
|
292 |
- |
293 |
--with-alsagconfdir and --with-alsalconfdir |
0 |
--with-alsagconfdir and --with-alsalconfdir |
294 |
-- |
|
|
295 |
a52/Makefile.am | 14 +++++++++++--- |
1 |
a52/Makefile.am | 14 +++++++++++--- |
296 |
arcam-av/Makefile.am | 14 +++++++++++--- |
2 |
arcam-av/Makefile.am | 14 +++++++++++--- |
297 |
configure.ac | 32 ++++++++++++++++++++++---------- |
3 |
configure.ac | 32 ++++++++++++++++++++++---------- |
298 |
install-hooks.am | 16 ++++++++++++++++ |
4 |
install-hooks.am | 16 ++++++++++++++++ |
299 |
jack/Makefile.am | 14 +++++++++++--- |
5 |
jack/Makefile.am | 14 +++++++++++--- |
300 |
maemo/Makefile.am | 14 +++++++++++--- |
6 |
maemo/Makefile.am | 14 +++++++++++--- |
301 |
mix/Makefile.am | 14 +++++++++++--- |
7 |
mix/Makefile.am | 14 +++++++++++--- |
302 |
oss/Makefile.am | 14 +++++++++++--- |
8 |
oss/Makefile.am | 14 +++++++++++--- |
303 |
pph/Makefile.am | 16 ++++++++++++---- |
9 |
pph/Makefile.am | 16 ++++++++++++---- |
304 |
pulse/Makefile.am | 17 ++++++++++++++--- |
10 |
pulse/Makefile.am | 17 ++++++++++++++--- |
305 |
rate-lav/Makefile.am | 13 ++++++++++--- |
11 |
rate-lav/Makefile.am | 13 ++++++++++--- |
306 |
rate/Makefile.am | 14 +++++++++++--- |
12 |
rate/Makefile.am | 14 +++++++++++--- |
307 |
speex/Makefile.am | 14 +++++++++++--- |
13 |
speex/Makefile.am | 14 +++++++++++--- |
308 |
usb_stream/Makefile.am | 14 +++++++++++--- |
14 |
usb_stream/Makefile.am | 14 +++++++++++--- |
309 |
14 files changed, 173 insertions(+), 47 deletions(-) |
15 |
14 files changed, 173 insertions(+), 47 deletions(-) |
310 |
create mode 100644 install-hooks.am |
16 |
create mode 100644 install-hooks.am |