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 <linux/time.h>
23 #include <sound/core.h>
24 #include <sound/pcm.h>
25 #include "pcm_plugin.h"
28 #define BITS (1<<SHIFT)
29 #define R_MASK (BITS-1)
32 * Basic rate conversion plugin
40 typedef void (*rate_f
)(struct snd_pcm_plugin
*plugin
,
41 const struct snd_pcm_plugin_channel
*src_channels
,
42 struct snd_pcm_plugin_channel
*dst_channels
,
43 int src_frames
, int dst_frames
);
49 snd_pcm_sframes_t old_src_frames
, old_dst_frames
;
50 struct rate_channel channels
[];
53 static void rate_init(struct snd_pcm_plugin
*plugin
)
56 struct rate_priv
*data
= (struct rate_priv
*)plugin
->extra_data
;
58 for (channel
= 0; channel
< plugin
->src_format
.channels
; channel
++) {
59 data
->channels
[channel
].last_S1
= 0;
60 data
->channels
[channel
].last_S2
= 0;
64 static void resample_expand(struct snd_pcm_plugin
*plugin
,
65 const struct snd_pcm_plugin_channel
*src_channels
,
66 struct snd_pcm_plugin_channel
*dst_channels
,
67 int src_frames
, int dst_frames
)
72 signed short *src
, *dst
;
74 int src_step
, dst_step
;
75 int src_frames1
, dst_frames1
;
76 struct rate_priv
*data
= (struct rate_priv
*)plugin
->extra_data
;
77 struct rate_channel
*rchannels
= data
->channels
;
79 for (channel
= 0; channel
< plugin
->src_format
.channels
; channel
++) {
81 S1
= rchannels
->last_S1
;
82 S2
= rchannels
->last_S2
;
83 if (!src_channels
[channel
].enabled
) {
84 if (dst_channels
[channel
].wanted
)
85 snd_pcm_area_silence(&dst_channels
[channel
].area
, 0, dst_frames
, plugin
->dst_format
.format
);
86 dst_channels
[channel
].enabled
= 0;
89 dst_channels
[channel
].enabled
= 1;
90 src
= (signed short *)src_channels
[channel
].area
.addr
+
91 src_channels
[channel
].area
.first
/ 8 / 2;
92 dst
= (signed short *)dst_channels
[channel
].area
.addr
+
93 dst_channels
[channel
].area
.first
/ 8 / 2;
94 src_step
= src_channels
[channel
].area
.step
/ 8 / 2;
95 dst_step
= dst_channels
[channel
].area
.step
/ 8 / 2;
96 src_frames1
= src_frames
;
97 dst_frames1
= dst_frames
;
98 while (dst_frames1
-- > 0) {
102 if (src_frames1
-- > 0) {
107 val
= S1
+ ((S2
- S1
) * (signed int)pos
) / BITS
;
110 else if (val
> 32767)
116 rchannels
->last_S1
= S1
;
117 rchannels
->last_S2
= S2
;
123 static void resample_shrink(struct snd_pcm_plugin
*plugin
,
124 const struct snd_pcm_plugin_channel
*src_channels
,
125 struct snd_pcm_plugin_channel
*dst_channels
,
126 int src_frames
, int dst_frames
)
128 unsigned int pos
= 0;
131 signed short *src
, *dst
;
132 unsigned int channel
;
133 int src_step
, dst_step
;
134 int src_frames1
, dst_frames1
;
135 struct rate_priv
*data
= (struct rate_priv
*)plugin
->extra_data
;
136 struct rate_channel
*rchannels
= data
->channels
;
138 for (channel
= 0; channel
< plugin
->src_format
.channels
; ++channel
) {
140 S1
= rchannels
->last_S1
;
141 S2
= rchannels
->last_S2
;
142 if (!src_channels
[channel
].enabled
) {
143 if (dst_channels
[channel
].wanted
)
144 snd_pcm_area_silence(&dst_channels
[channel
].area
, 0, dst_frames
, plugin
->dst_format
.format
);
145 dst_channels
[channel
].enabled
= 0;
148 dst_channels
[channel
].enabled
= 1;
149 src
= (signed short *)src_channels
[channel
].area
.addr
+
150 src_channels
[channel
].area
.first
/ 8 / 2;
151 dst
= (signed short *)dst_channels
[channel
].area
.addr
+
152 dst_channels
[channel
].area
.first
/ 8 / 2;
153 src_step
= src_channels
[channel
].area
.step
/ 8 / 2;
154 dst_step
= dst_channels
[channel
].area
.step
/ 8 / 2;
155 src_frames1
= src_frames
;
156 dst_frames1
= dst_frames
;
157 while (dst_frames1
> 0) {
159 if (src_frames1
-- > 0) {
165 val
= S1
+ ((S2
- S1
) * (signed int)pos
) / BITS
;
168 else if (val
> 32767)
176 rchannels
->last_S1
= S1
;
177 rchannels
->last_S2
= S2
;
183 static snd_pcm_sframes_t
rate_src_frames(struct snd_pcm_plugin
*plugin
, snd_pcm_uframes_t frames
)
185 struct rate_priv
*data
;
186 snd_pcm_sframes_t res
;
188 if (snd_BUG_ON(!plugin
))
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 if (snd_BUG_ON(!plugin
))
225 data
= (struct rate_priv
*)plugin
->extra_data
;
226 if (plugin
->src_format
.rate
< plugin
->dst_format
.rate
) {
227 res
= (((frames
<< SHIFT
) + (data
->pitch
/ 2)) / data
->pitch
);
229 res
= (((frames
* data
->pitch
) + (BITS
/2)) >> SHIFT
);
231 if (data
->old_dst_frames
> 0) {
232 snd_pcm_sframes_t frames1
= frames
, res1
= data
->old_src_frames
;
233 while (data
->old_dst_frames
< frames1
) {
237 while (data
->old_dst_frames
> frames1
) {
241 if (data
->old_dst_frames
== frames1
)
244 data
->old_dst_frames
= frames
;
245 data
->old_src_frames
= res
;
249 static snd_pcm_sframes_t
rate_transfer(struct snd_pcm_plugin
*plugin
,
250 const struct snd_pcm_plugin_channel
*src_channels
,
251 struct snd_pcm_plugin_channel
*dst_channels
,
252 snd_pcm_uframes_t frames
)
254 snd_pcm_uframes_t dst_frames
;
255 struct rate_priv
*data
;
257 if (snd_BUG_ON(!plugin
|| !src_channels
|| !dst_channels
))
261 #ifdef CONFIG_SND_DEBUG
263 unsigned int channel
;
264 for (channel
= 0; channel
< plugin
->src_format
.channels
; channel
++) {
265 if (snd_BUG_ON(src_channels
[channel
].area
.first
% 8 ||
266 src_channels
[channel
].area
.step
% 8))
268 if (snd_BUG_ON(dst_channels
[channel
].area
.first
% 8 ||
269 dst_channels
[channel
].area
.step
% 8))
275 dst_frames
= rate_dst_frames(plugin
, frames
);
276 if (dst_frames
> dst_channels
[0].frames
)
277 dst_frames
= dst_channels
[0].frames
;
278 data
= (struct rate_priv
*)plugin
->extra_data
;
279 data
->func(plugin
, src_channels
, dst_channels
, frames
, dst_frames
);
283 static int rate_action(struct snd_pcm_plugin
*plugin
,
284 enum snd_pcm_plugin_action action
,
287 if (snd_BUG_ON(!plugin
))
297 return 0; /* silenty ignore other actions */
300 int snd_pcm_plugin_build_rate(struct snd_pcm_substream
*plug
,
301 struct snd_pcm_plugin_format
*src_format
,
302 struct snd_pcm_plugin_format
*dst_format
,
303 struct snd_pcm_plugin
**r_plugin
)
306 struct rate_priv
*data
;
307 struct snd_pcm_plugin
*plugin
;
309 if (snd_BUG_ON(!r_plugin
))
313 if (snd_BUG_ON(src_format
->channels
!= dst_format
->channels
))
315 if (snd_BUG_ON(src_format
->channels
<= 0))
317 if (snd_BUG_ON(src_format
->format
!= SNDRV_PCM_FORMAT_S16
))
319 if (snd_BUG_ON(dst_format
->format
!= SNDRV_PCM_FORMAT_S16
))
321 if (snd_BUG_ON(src_format
->rate
== dst_format
->rate
))
324 err
= snd_pcm_plugin_build(plug
, "rate conversion",
325 src_format
, dst_format
,
326 struct_size(data
, channels
,
327 src_format
->channels
),
331 data
= (struct rate_priv
*)plugin
->extra_data
;
332 if (src_format
->rate
< dst_format
->rate
) {
333 data
->pitch
= ((src_format
->rate
<< SHIFT
) + (dst_format
->rate
>> 1)) / dst_format
->rate
;
334 data
->func
= resample_expand
;
336 data
->pitch
= ((dst_format
->rate
<< SHIFT
) + (src_format
->rate
>> 1)) / src_format
->rate
;
337 data
->func
= resample_shrink
;
341 data
->old_src_frames
= data
->old_dst_frames
= 0;
342 plugin
->transfer
= rate_transfer
;
343 plugin
->src_frames
= rate_src_frames
;
344 plugin
->dst_frames
= rate_dst_frames
;
345 plugin
->action
= rate_action
;