2 * Rate converter plugin using libsamplerate
4 * Copyright (c) 2006 by Takashi Iwai <tiwai@suse.de>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
18 #include <samplerate.h>
19 #include <alsa/asoundlib.h>
20 #include <alsa/pcm_rate.h>
26 unsigned int channels;
35 static snd_pcm_uframes_t input_frames(void *obj, snd_pcm_uframes_t frames)
37 struct rate_src *rate = obj;
40 return (snd_pcm_uframes_t)(frames / rate->ratio);
43 static snd_pcm_uframes_t output_frames(void *obj, snd_pcm_uframes_t frames)
45 struct rate_src *rate = obj;
48 return (snd_pcm_uframes_t)(frames * rate->ratio);
51 static void pcm_src_free(void *obj)
53 struct rate_src *rate = obj;
57 rate->src_buf = rate->dst_buf = NULL;
60 src_delete(rate->state);
65 static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info)
67 struct rate_src *rate = obj;
70 if (! rate->state || rate->channels != info->channels) {
72 src_delete(rate->state);
73 rate->channels = info->channels;
74 rate->state = src_new(rate->converter, rate->channels, &err);
79 rate->ratio = (double)info->out.rate / (double)info->in.rate;
82 rate->src_buf = malloc(sizeof(float) * rate->channels * info->in.period_size);
84 rate->dst_buf = malloc(sizeof(float) * rate->channels * info->out.period_size);
85 if (! rate->src_buf || ! rate->dst_buf) {
90 rate->data.data_in = rate->src_buf;
91 rate->data.data_out = rate->dst_buf;
92 rate->data.src_ratio = rate->ratio;
93 rate->data.end_of_input = 0;
95 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003
96 if (rate->version >= 0x010003) {
97 rate->in_int = info->in.format == SND_PCM_FORMAT_S32;
98 rate->out_int = info->out.format == SND_PCM_FORMAT_S32;
105 static int pcm_src_adjust_pitch(void *obj, snd_pcm_rate_info_t *info)
107 struct rate_src *rate = obj;
109 rate->ratio = ((double)info->out.period_size / (double)info->in.period_size);
110 rate->data.src_ratio = rate->ratio;
114 static void pcm_src_reset(void *obj)
116 struct rate_src *rate = obj;
118 src_reset(rate->state);
121 static void do_convert(struct rate_src *rate,
122 void *dst, unsigned int dst_frames,
123 const void *src, unsigned int src_frames)
127 rate->data.input_frames = src_frames;
128 rate->data.output_frames = dst_frames;
129 rate->data.end_of_input = 0;
132 src_int_to_float_array(src, rate->src_buf, src_frames * rate->channels);
134 src_short_to_float_array(src, rate->src_buf, src_frames * rate->channels);
135 src_process(rate->state, &rate->data);
136 if (rate->data.output_frames_gen < dst_frames)
137 ofs = dst_frames - rate->data.output_frames_gen;
141 src_float_to_int_array(rate->dst_buf, dst + ofs * rate->channels * 4,
142 rate->data.output_frames_gen * rate->channels);
144 src_float_to_short_array(rate->dst_buf, dst + ofs * rate->channels * 2,
145 rate->data.output_frames_gen * rate->channels);
148 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003
149 static void pcm_src_convert(void *obj,
150 const snd_pcm_channel_area_t *dst_areas,
151 snd_pcm_uframes_t dst_offset,
152 unsigned int dst_frames,
153 const snd_pcm_channel_area_t *src_areas,
154 snd_pcm_uframes_t src_offset,
155 unsigned int src_frames)
157 struct rate_src *rate = obj;
158 const void *src = snd_pcm_channel_area_addr(src_areas, src_offset);
159 void *dst = snd_pcm_channel_area_addr(dst_areas, dst_offset);
161 do_convert(rate, dst, dst_frames, src, src_frames);
165 static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int dst_frames,
166 const int16_t *src, unsigned int src_frames)
168 struct rate_src *rate = obj;
170 do_convert(rate, dst, dst_frames, src, src_frames);
173 static void pcm_src_close(void *obj)
178 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
179 static int get_supported_rates(void *obj ATTRIBUTE_UNUSED, unsigned int *rate_min,
180 unsigned int *rate_max)
182 *rate_min = *rate_max = 0; /* both unlimited */
186 static void dump(void *obj ATTRIBUTE_UNUSED, snd_output_t *out)
188 snd_output_printf(out, "Converter: libsamplerate\n");
192 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003
193 static int get_supported_formats(void *obj, uint64_t *in_formats,
194 uint64_t *out_formats,
197 *in_formats = *out_formats =
198 (1ULL << SND_PCM_FORMAT_S16) |
199 (1ULL << SND_PCM_FORMAT_S32);
200 *flags = SND_PCM_RATE_FLAG_INTERLEAVED;
205 static snd_pcm_rate_ops_t pcm_src_ops = {
206 .close = pcm_src_close,
207 .init = pcm_src_init,
208 .free = pcm_src_free,
209 .reset = pcm_src_reset,
210 .adjust_pitch = pcm_src_adjust_pitch,
211 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003
212 .convert = pcm_src_convert,
214 .convert_s16 = pcm_src_convert_s16,
215 .input_frames = input_frames,
216 .output_frames = output_frames,
217 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
218 .version = SND_PCM_RATE_PLUGIN_VERSION,
219 .get_supported_rates = get_supported_rates,
222 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003
223 .get_supported_formats = get_supported_formats,
227 static int pcm_src_open(unsigned int version, void **objp,
228 snd_pcm_rate_ops_t *ops, int type)
230 struct rate_src *rate;
232 rate = calloc(1, sizeof(*rate));
236 rate->version = version;
237 rate->converter = type;
240 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
241 if (version == 0x010001) {
242 memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t));
246 #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003
247 if (version == 0x010002) {
248 memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_v2_ops_t));
256 int SND_PCM_RATE_PLUGIN_ENTRY(samplerate) (unsigned int version, void **objp,
257 snd_pcm_rate_ops_t *ops)
259 return pcm_src_open(version, objp, ops, SRC_SINC_FASTEST);
262 int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_best) (unsigned int version, void **objp,
263 snd_pcm_rate_ops_t *ops)
265 return pcm_src_open(version, objp, ops, SRC_SINC_BEST_QUALITY);
268 int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_medium) (unsigned int version, void **objp,
269 snd_pcm_rate_ops_t *ops)
271 return pcm_src_open(version, objp, ops, SRC_SINC_MEDIUM_QUALITY);
274 int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_order) (unsigned int version, void **objp,
275 snd_pcm_rate_ops_t *ops)
277 return pcm_src_open(version, objp, ops, SRC_ZERO_ORDER_HOLD);
280 int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_linear) (unsigned int version, void **objp,
281 snd_pcm_rate_ops_t *ops)
283 return pcm_src_open(version, objp, ops, SRC_LINEAR);