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
[0];
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 snd_assert(plugin
!= NULL
, return -ENXIO
);
191 data
= (struct rate_priv
*)plugin
->extra_data
;
192 if (plugin
->src_format
.rate
< plugin
->dst_format
.rate
) {
193 res
= (((frames
* data
->pitch
) + (BITS
/2)) >> SHIFT
);
195 res
= (((frames
<< SHIFT
) + (data
->pitch
/ 2)) / data
->pitch
);
197 if (data
->old_src_frames
> 0) {
198 snd_pcm_sframes_t frames1
= frames
, res1
= data
->old_dst_frames
;
199 while (data
->old_src_frames
< frames1
) {
203 while (data
->old_src_frames
> frames1
) {
207 if (data
->old_src_frames
== frames1
)
210 data
->old_src_frames
= frames
;
211 data
->old_dst_frames
= res
;
215 static snd_pcm_sframes_t
rate_dst_frames(struct snd_pcm_plugin
*plugin
, snd_pcm_uframes_t frames
)
217 struct rate_priv
*data
;
218 snd_pcm_sframes_t res
;
220 snd_assert(plugin
!= NULL
, return -ENXIO
);
223 data
= (struct rate_priv
*)plugin
->extra_data
;
224 if (plugin
->src_format
.rate
< plugin
->dst_format
.rate
) {
225 res
= (((frames
<< SHIFT
) + (data
->pitch
/ 2)) / data
->pitch
);
227 res
= (((frames
* data
->pitch
) + (BITS
/2)) >> SHIFT
);
229 if (data
->old_dst_frames
> 0) {
230 snd_pcm_sframes_t frames1
= frames
, res1
= data
->old_src_frames
;
231 while (data
->old_dst_frames
< frames1
) {
235 while (data
->old_dst_frames
> frames1
) {
239 if (data
->old_dst_frames
== frames1
)
242 data
->old_dst_frames
= frames
;
243 data
->old_src_frames
= res
;
247 static snd_pcm_sframes_t
rate_transfer(struct snd_pcm_plugin
*plugin
,
248 const struct snd_pcm_plugin_channel
*src_channels
,
249 struct snd_pcm_plugin_channel
*dst_channels
,
250 snd_pcm_uframes_t frames
)
252 snd_pcm_uframes_t dst_frames
;
253 struct rate_priv
*data
;
255 snd_assert(plugin
!= NULL
&& src_channels
!= NULL
&& dst_channels
!= NULL
, return -ENXIO
);
258 #ifdef CONFIG_SND_DEBUG
260 unsigned int channel
;
261 for (channel
= 0; channel
< plugin
->src_format
.channels
; channel
++) {
262 snd_assert(src_channels
[channel
].area
.first
% 8 == 0 &&
263 src_channels
[channel
].area
.step
% 8 == 0,
265 snd_assert(dst_channels
[channel
].area
.first
% 8 == 0 &&
266 dst_channels
[channel
].area
.step
% 8 == 0,
272 dst_frames
= rate_dst_frames(plugin
, frames
);
273 if (dst_frames
> dst_channels
[0].frames
)
274 dst_frames
= dst_channels
[0].frames
;
275 data
= (struct rate_priv
*)plugin
->extra_data
;
276 data
->func(plugin
, src_channels
, dst_channels
, frames
, dst_frames
);
280 static int rate_action(struct snd_pcm_plugin
*plugin
,
281 enum snd_pcm_plugin_action action
,
284 snd_assert(plugin
!= NULL
, return -ENXIO
);
293 return 0; /* silenty ignore other actions */
296 int snd_pcm_plugin_build_rate(struct snd_pcm_substream
*plug
,
297 struct snd_pcm_plugin_format
*src_format
,
298 struct snd_pcm_plugin_format
*dst_format
,
299 struct snd_pcm_plugin
**r_plugin
)
302 struct rate_priv
*data
;
303 struct snd_pcm_plugin
*plugin
;
305 snd_assert(r_plugin
!= NULL
, return -ENXIO
);
308 snd_assert(src_format
->channels
== dst_format
->channels
, return -ENXIO
);
309 snd_assert(src_format
->channels
> 0, return -ENXIO
);
310 snd_assert(src_format
->format
== SNDRV_PCM_FORMAT_S16
, return -ENXIO
);
311 snd_assert(dst_format
->format
== SNDRV_PCM_FORMAT_S16
, return -ENXIO
);
312 snd_assert(src_format
->rate
!= dst_format
->rate
, return -ENXIO
);
314 err
= snd_pcm_plugin_build(plug
, "rate conversion",
315 src_format
, dst_format
,
316 sizeof(struct rate_priv
) +
317 src_format
->channels
* sizeof(struct rate_channel
),
321 data
= (struct rate_priv
*)plugin
->extra_data
;
322 if (src_format
->rate
< dst_format
->rate
) {
323 data
->pitch
= ((src_format
->rate
<< SHIFT
) + (dst_format
->rate
>> 1)) / dst_format
->rate
;
324 data
->func
= resample_expand
;
326 data
->pitch
= ((dst_format
->rate
<< SHIFT
) + (src_format
->rate
>> 1)) / src_format
->rate
;
327 data
->func
= resample_shrink
;
331 data
->old_src_frames
= data
->old_dst_frames
= 0;
332 plugin
->transfer
= rate_transfer
;
333 plugin
->src_frames
= rate_src_frames
;
334 plugin
->dst_frames
= rate_dst_frames
;
335 plugin
->action
= rate_action
;