2 * Rate conversion Plug-In
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program 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
14 * GNU Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <sound/driver.h>
23 #include <linux/time.h>
24 #include <sound/core.h>
25 #include <sound/pcm.h>
26 #include "pcm_plugin.h"
29 #define BITS (1<<SHIFT)
30 #define R_MASK (BITS-1)
33 * Basic rate conversion plugin
41 typedef void (*rate_f
)(struct snd_pcm_plugin
*plugin
,
42 const struct snd_pcm_plugin_channel
*src_channels
,
43 struct snd_pcm_plugin_channel
*dst_channels
,
44 int src_frames
, int dst_frames
);
50 snd_pcm_sframes_t old_src_frames
, old_dst_frames
;
51 struct rate_channel channels
[0];
54 static void rate_init(struct snd_pcm_plugin
*plugin
)
57 struct rate_priv
*data
= (struct rate_priv
*)plugin
->extra_data
;
59 for (channel
= 0; channel
< plugin
->src_format
.channels
; channel
++) {
60 data
->channels
[channel
].last_S1
= 0;
61 data
->channels
[channel
].last_S2
= 0;
65 static void resample_expand(struct snd_pcm_plugin
*plugin
,
66 const struct snd_pcm_plugin_channel
*src_channels
,
67 struct snd_pcm_plugin_channel
*dst_channels
,
68 int src_frames
, int dst_frames
)
73 signed short *src
, *dst
;
75 int src_step
, dst_step
;
76 int src_frames1
, dst_frames1
;
77 struct rate_priv
*data
= (struct rate_priv
*)plugin
->extra_data
;
78 struct rate_channel
*rchannels
= data
->channels
;
80 for (channel
= 0; channel
< plugin
->src_format
.channels
; channel
++) {
82 S1
= rchannels
->last_S1
;
83 S2
= rchannels
->last_S2
;
84 if (!src_channels
[channel
].enabled
) {
85 if (dst_channels
[channel
].wanted
)
86 snd_pcm_area_silence(&dst_channels
[channel
].area
, 0, dst_frames
, plugin
->dst_format
.format
);
87 dst_channels
[channel
].enabled
= 0;
90 dst_channels
[channel
].enabled
= 1;
91 src
= (signed short *)src_channels
[channel
].area
.addr
+
92 src_channels
[channel
].area
.first
/ 8 / 2;
93 dst
= (signed short *)dst_channels
[channel
].area
.addr
+
94 dst_channels
[channel
].area
.first
/ 8 / 2;
95 src_step
= src_channels
[channel
].area
.step
/ 8 / 2;
96 dst_step
= dst_channels
[channel
].area
.step
/ 8 / 2;
97 src_frames1
= src_frames
;
98 dst_frames1
= dst_frames
;
99 while (dst_frames1
-- > 0) {
103 if (src_frames1
-- > 0) {
108 val
= S1
+ ((S2
- S1
) * (signed int)pos
) / BITS
;
111 else if (val
> 32767)
117 rchannels
->last_S1
= S1
;
118 rchannels
->last_S2
= S2
;
124 static void resample_shrink(struct snd_pcm_plugin
*plugin
,
125 const struct snd_pcm_plugin_channel
*src_channels
,
126 struct snd_pcm_plugin_channel
*dst_channels
,
127 int src_frames
, int dst_frames
)
129 unsigned int pos
= 0;
132 signed short *src
, *dst
;
133 unsigned int channel
;
134 int src_step
, dst_step
;
135 int src_frames1
, dst_frames1
;
136 struct rate_priv
*data
= (struct rate_priv
*)plugin
->extra_data
;
137 struct rate_channel
*rchannels
= data
->channels
;
139 for (channel
= 0; channel
< plugin
->src_format
.channels
; ++channel
) {
141 S1
= rchannels
->last_S1
;
142 S2
= rchannels
->last_S2
;
143 if (!src_channels
[channel
].enabled
) {
144 if (dst_channels
[channel
].wanted
)
145 snd_pcm_area_silence(&dst_channels
[channel
].area
, 0, dst_frames
, plugin
->dst_format
.format
);
146 dst_channels
[channel
].enabled
= 0;
149 dst_channels
[channel
].enabled
= 1;
150 src
= (signed short *)src_channels
[channel
].area
.addr
+
151 src_channels
[channel
].area
.first
/ 8 / 2;
152 dst
= (signed short *)dst_channels
[channel
].area
.addr
+
153 dst_channels
[channel
].area
.first
/ 8 / 2;
154 src_step
= src_channels
[channel
].area
.step
/ 8 / 2;
155 dst_step
= dst_channels
[channel
].area
.step
/ 8 / 2;
156 src_frames1
= src_frames
;
157 dst_frames1
= dst_frames
;
158 while (dst_frames1
> 0) {
160 if (src_frames1
-- > 0) {
166 val
= S1
+ ((S2
- S1
) * (signed int)pos
) / BITS
;
169 else if (val
> 32767)
177 rchannels
->last_S1
= S1
;
178 rchannels
->last_S2
= S2
;
184 static snd_pcm_sframes_t
rate_src_frames(struct snd_pcm_plugin
*plugin
, snd_pcm_uframes_t frames
)
186 struct rate_priv
*data
;
187 snd_pcm_sframes_t res
;
189 snd_assert(plugin
!= NULL
, return -ENXIO
);
192 data
= (struct rate_priv
*)plugin
->extra_data
;
193 if (plugin
->src_format
.rate
< plugin
->dst_format
.rate
) {
194 res
= (((frames
* data
->pitch
) + (BITS
/2)) >> SHIFT
);
196 res
= (((frames
<< SHIFT
) + (data
->pitch
/ 2)) / data
->pitch
);
198 if (data
->old_src_frames
> 0) {
199 snd_pcm_sframes_t frames1
= frames
, res1
= data
->old_dst_frames
;
200 while (data
->old_src_frames
< frames1
) {
204 while (data
->old_src_frames
> frames1
) {
208 if (data
->old_src_frames
== frames1
)
211 data
->old_src_frames
= frames
;
212 data
->old_dst_frames
= res
;
216 static snd_pcm_sframes_t
rate_dst_frames(struct snd_pcm_plugin
*plugin
, snd_pcm_uframes_t frames
)
218 struct rate_priv
*data
;
219 snd_pcm_sframes_t res
;
221 snd_assert(plugin
!= NULL
, return -ENXIO
);
224 data
= (struct rate_priv
*)plugin
->extra_data
;
225 if (plugin
->src_format
.rate
< plugin
->dst_format
.rate
) {
226 res
= (((frames
<< SHIFT
) + (data
->pitch
/ 2)) / data
->pitch
);
228 res
= (((frames
* data
->pitch
) + (BITS
/2)) >> SHIFT
);
230 if (data
->old_dst_frames
> 0) {
231 snd_pcm_sframes_t frames1
= frames
, res1
= data
->old_src_frames
;
232 while (data
->old_dst_frames
< frames1
) {
236 while (data
->old_dst_frames
> frames1
) {
240 if (data
->old_dst_frames
== frames1
)
243 data
->old_dst_frames
= frames
;
244 data
->old_src_frames
= res
;
248 static snd_pcm_sframes_t
rate_transfer(struct snd_pcm_plugin
*plugin
,
249 const struct snd_pcm_plugin_channel
*src_channels
,
250 struct snd_pcm_plugin_channel
*dst_channels
,
251 snd_pcm_uframes_t frames
)
253 snd_pcm_uframes_t dst_frames
;
254 struct rate_priv
*data
;
256 snd_assert(plugin
!= NULL
&& src_channels
!= NULL
&& dst_channels
!= NULL
, return -ENXIO
);
259 #ifdef CONFIG_SND_DEBUG
261 unsigned int channel
;
262 for (channel
= 0; channel
< plugin
->src_format
.channels
; channel
++) {
263 snd_assert(src_channels
[channel
].area
.first
% 8 == 0 &&
264 src_channels
[channel
].area
.step
% 8 == 0,
266 snd_assert(dst_channels
[channel
].area
.first
% 8 == 0 &&
267 dst_channels
[channel
].area
.step
% 8 == 0,
273 dst_frames
= rate_dst_frames(plugin
, frames
);
274 if (dst_frames
> dst_channels
[0].frames
)
275 dst_frames
= dst_channels
[0].frames
;
276 data
= (struct rate_priv
*)plugin
->extra_data
;
277 data
->func(plugin
, src_channels
, dst_channels
, frames
, dst_frames
);
281 static int rate_action(struct snd_pcm_plugin
*plugin
,
282 enum snd_pcm_plugin_action action
,
285 snd_assert(plugin
!= NULL
, return -ENXIO
);
294 return 0; /* silenty ignore other actions */
297 int snd_pcm_plugin_build_rate(struct snd_pcm_substream
*plug
,
298 struct snd_pcm_plugin_format
*src_format
,
299 struct snd_pcm_plugin_format
*dst_format
,
300 struct snd_pcm_plugin
**r_plugin
)
303 struct rate_priv
*data
;
304 struct snd_pcm_plugin
*plugin
;
306 snd_assert(r_plugin
!= NULL
, return -ENXIO
);
309 snd_assert(src_format
->channels
== dst_format
->channels
, return -ENXIO
);
310 snd_assert(src_format
->channels
> 0, return -ENXIO
);
311 snd_assert(src_format
->format
== SNDRV_PCM_FORMAT_S16
, return -ENXIO
);
312 snd_assert(dst_format
->format
== SNDRV_PCM_FORMAT_S16
, return -ENXIO
);
313 snd_assert(src_format
->rate
!= dst_format
->rate
, return -ENXIO
);
315 err
= snd_pcm_plugin_build(plug
, "rate conversion",
316 src_format
, dst_format
,
317 sizeof(struct rate_priv
) +
318 src_format
->channels
* sizeof(struct rate_channel
),
322 data
= (struct rate_priv
*)plugin
->extra_data
;
323 if (src_format
->rate
< dst_format
->rate
) {
324 data
->pitch
= ((src_format
->rate
<< SHIFT
) + (dst_format
->rate
>> 1)) / dst_format
->rate
;
325 data
->func
= resample_expand
;
327 data
->pitch
= ((dst_format
->rate
<< SHIFT
) + (src_format
->rate
>> 1)) / src_format
->rate
;
328 data
->func
= resample_shrink
;
332 data
->old_src_frames
= data
->old_dst_frames
= 0;
333 plugin
->transfer
= rate_transfer
;
334 plugin
->src_frames
= rate_src_frames
;
335 plugin
->dst_frames
= rate_dst_frames
;
336 plugin
->action
= rate_action
;