resetting manifest requested domain to floor
[platform/upstream/alsa-plugins.git] / rate-lavc / rate_lavcrate.c
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