2 * Attenuated route Plug-In
3 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
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>
24 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
26 #include <linux/slab.h>
27 #include <linux/time.h>
28 #include <sound/core.h>
29 #include <sound/pcm.h>
30 #include "pcm_plugin.h"
32 /* The best possible hack to support missing optimization in gcc 2.7.2.3 */
33 #if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0
34 #define div(a) a /= ROUTE_PLUGIN_RESOLUTION
35 #elif ROUTE_PLUGIN_RESOLUTION == 16
36 #define div(a) a >>= 4
38 #error "Add some code here"
43 typedef void (*route_channel_f
)(struct snd_pcm_plugin
*plugin
,
44 const struct snd_pcm_plugin_channel
*src_channels
,
45 struct snd_pcm_plugin_channel
*dst_channel
,
46 struct ttable_dst
*ttable
, snd_pcm_uframes_t frames
);
54 int att
; /* Attenuated */
56 struct ttable_src
*srcs
;
61 enum {R_UINT32
=0, R_UINT64
=1} sum_type
;
65 struct ttable_dst ttable
[0];
74 static void route_to_channel_from_zero(struct snd_pcm_plugin
*plugin
,
75 const struct snd_pcm_plugin_channel
*src_channels
,
76 struct snd_pcm_plugin_channel
*dst_channel
,
77 struct ttable_dst
*ttable
,
78 snd_pcm_uframes_t frames
)
80 if (dst_channel
->wanted
)
81 snd_pcm_area_silence(&dst_channel
->area
, 0, frames
, plugin
->dst_format
.format
);
82 dst_channel
->enabled
= 0;
85 static void route_to_channel_from_one(struct snd_pcm_plugin
*plugin
,
86 const struct snd_pcm_plugin_channel
*src_channels
,
87 struct snd_pcm_plugin_channel
*dst_channel
,
88 struct ttable_dst
*ttable
,
89 snd_pcm_uframes_t frames
)
92 #include "plugin_ops.h"
94 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
96 const struct snd_pcm_plugin_channel
*src_channel
= NULL
;
99 int src_step
, dst_step
;
100 for (srcidx
= 0; srcidx
< ttable
->nsrcs
; ++srcidx
) {
101 src_channel
= &src_channels
[ttable
->srcs
[srcidx
].channel
];
102 if (src_channel
->area
.addr
!= NULL
)
105 if (srcidx
== ttable
->nsrcs
) {
106 route_to_channel_from_zero(plugin
, src_channels
, dst_channel
, ttable
, frames
);
110 dst_channel
->enabled
= 1;
111 conv
= conv_labels
[data
->conv
];
112 src
= src_channel
->area
.addr
+ src_channel
->area
.first
/ 8;
113 src_step
= src_channel
->area
.step
/ 8;
114 dst
= dst_channel
->area
.addr
+ dst_channel
->area
.first
/ 8;
115 dst_step
= dst_channel
->area
.step
/ 8;
116 while (frames
-- > 0) {
118 #define CONV_END after
119 #include "plugin_ops.h"
127 static void route_to_channel(struct snd_pcm_plugin
*plugin
,
128 const struct snd_pcm_plugin_channel
*src_channels
,
129 struct snd_pcm_plugin_channel
*dst_channel
,
130 struct ttable_dst
*ttable
, snd_pcm_uframes_t frames
)
133 #define PUT_U32_LABELS
134 #include "plugin_ops.h"
136 #undef PUT_U32_LABELS
137 static void *zero_labels
[2] = { &&zero_int32
, &&zero_int64
};
139 static void *add_labels
[2 * 2] = { &&add_int32_noatt
, &&add_int32_att
,
140 &&add_int64_noatt
, &&add_int64_att
,
142 /* sum_type att shift */
143 static void *norm_labels
[2 * 2 * 4] = { NULL
,
144 &&norm_int32_8_noatt
,
145 &&norm_int32_16_noatt
,
146 &&norm_int32_24_noatt
,
151 &&norm_int64_0_noatt
,
152 &&norm_int64_8_noatt
,
153 &&norm_int64_16_noatt
,
154 &&norm_int64_24_noatt
,
160 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
161 void *zero
, *get
, *add
, *norm
, *put_u32
;
162 int nsrcs
= ttable
->nsrcs
;
166 int src_steps
[nsrcs
];
167 struct ttable_src src_tt
[nsrcs
];
168 u_int32_t sample
= 0;
169 int srcidx
, srcidx1
= 0;
170 for (srcidx
= 0; srcidx
< nsrcs
; ++srcidx
) {
171 const struct snd_pcm_plugin_channel
*src_channel
= &src_channels
[ttable
->srcs
[srcidx
].channel
];
172 if (!src_channel
->enabled
)
174 srcs
[srcidx1
] = src_channel
->area
.addr
+ src_channel
->area
.first
/ 8;
175 src_steps
[srcidx1
] = src_channel
->area
.step
/ 8;
176 src_tt
[srcidx1
] = ttable
->srcs
[srcidx
];
181 route_to_channel_from_zero(plugin
, src_channels
, dst_channel
, ttable
, frames
);
183 } else if (nsrcs
== 1 && src_tt
[0].as_int
== ROUTE_PLUGIN_RESOLUTION
) {
184 route_to_channel_from_one(plugin
, src_channels
, dst_channel
, ttable
, frames
);
188 dst_channel
->enabled
= 1;
189 zero
= zero_labels
[data
->sum_type
];
190 get
= get_u_labels
[data
->get
];
191 add
= add_labels
[data
->sum_type
* 2 + ttable
->att
];
192 norm
= norm_labels
[data
->sum_type
* 8 + ttable
->att
* 4 + 4 - data
->src_sample_size
];
193 put_u32
= put_u32_labels
[data
->put
];
194 dst
= dst_channel
->area
.addr
+ dst_channel
->area
.first
/ 8;
195 dst_step
= dst_channel
->area
.step
/ 8;
197 while (frames
-- > 0) {
198 struct ttable_src
*ttp
= src_tt
;
210 for (srcidx
= 0; srcidx
< nsrcs
; ++srcidx
) {
211 char *src
= srcs
[srcidx
];
215 #define GET_U_END after_get
216 #include "plugin_ops.h"
223 sum
.as_uint32
+= sample
* ttp
->as_int
;
227 sum
.as_uint32
+= sample
;
230 sum
.as_uint64
+= (u_int64_t
) sample
* ttp
->as_int
;
234 sum
.as_uint64
+= sample
;
237 srcs
[srcidx
] += src_steps
[srcidx
];
244 sum
.as_uint64
= sum
.as_uint32
;
252 sum
.as_uint64
= sum
.as_uint32
;
254 sum
.as_uint64
<<= 16;
259 sum
.as_uint64
= sum
.as_uint32
;
261 sum
.as_uint64
<<= 24;
266 sum
.as_uint64
= sum
.as_uint32
;
272 sum
.as_uint64
= sum
.as_uint32
;
274 sum
.as_uint64
<<= 16;
278 sum
.as_uint64
= sum
.as_uint32
;
280 sum
.as_uint64
<<= 24;
285 if (sum
.as_uint64
> (u_int32_t
)0xffffffff)
286 sample
= (u_int32_t
)0xffffffff;
288 sample
= sum
.as_uint64
;
295 #define PUT_U32_END after_put_u32
296 #include "plugin_ops.h"
304 static int route_src_channels_mask(struct snd_pcm_plugin
*plugin
,
305 unsigned long *dst_vmask
,
306 unsigned long **src_vmask
)
308 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
309 int schannels
= plugin
->src_format
.channels
;
310 int dchannels
= plugin
->dst_format
.channels
;
311 unsigned long *vmask
= plugin
->src_vmask
;
313 struct ttable_dst
*dp
= data
->ttable
;
314 bitmap_zero(vmask
, schannels
);
315 for (channel
= 0; channel
< dchannels
; channel
++, dp
++) {
317 struct ttable_src
*sp
;
318 if (!test_bit(channel
, dst_vmask
))
321 for (src
= 0; src
< dp
->nsrcs
; src
++, sp
++)
322 set_bit(sp
->channel
, vmask
);
328 static int route_dst_channels_mask(struct snd_pcm_plugin
*plugin
,
329 unsigned long *src_vmask
,
330 unsigned long **dst_vmask
)
332 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
333 int dchannels
= plugin
->dst_format
.channels
;
334 unsigned long *vmask
= plugin
->dst_vmask
;
336 struct ttable_dst
*dp
= data
->ttable
;
337 bitmap_zero(vmask
, dchannels
);
338 for (channel
= 0; channel
< dchannels
; channel
++, dp
++) {
340 struct ttable_src
*sp
;
342 for (src
= 0; src
< dp
->nsrcs
; src
++, sp
++) {
343 if (test_bit(sp
->channel
, src_vmask
)) {
344 set_bit(channel
, vmask
);
353 static void route_free(struct snd_pcm_plugin
*plugin
)
355 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
356 unsigned int dst_channel
;
357 for (dst_channel
= 0; dst_channel
< plugin
->dst_format
.channels
; ++dst_channel
) {
358 kfree(data
->ttable
[dst_channel
].srcs
);
362 static int route_load_ttable(struct snd_pcm_plugin
*plugin
,
363 const int *src_ttable
)
365 struct route_priv
*data
;
366 unsigned int src_channel
, dst_channel
;
368 struct ttable_dst
*dptr
;
369 if (src_ttable
== NULL
)
371 data
= (struct route_priv
*)plugin
->extra_data
;
374 plugin
->private_free
= route_free
;
375 for (dst_channel
= 0; dst_channel
< plugin
->dst_format
.channels
; ++dst_channel
) {
379 struct ttable_src srcs
[plugin
->src_format
.channels
];
380 for (src_channel
= 0; src_channel
< plugin
->src_format
.channels
; ++src_channel
) {
381 snd_assert(*sptr
>= 0 || *sptr
<= FULL
, return -ENXIO
);
383 srcs
[nsrcs
].channel
= src_channel
;
384 srcs
[nsrcs
].as_int
= *sptr
;
395 dptr
->func
= route_to_channel_from_zero
;
396 else if (nsrcs
== 1 && !att
)
397 dptr
->func
= route_to_channel_from_one
;
399 dptr
->func
= route_to_channel
;
402 dptr
->srcs
= kcalloc(nsrcs
, sizeof(*srcs
), GFP_KERNEL
);
403 for(srcidx
= 0; srcidx
< nsrcs
; srcidx
++)
404 dptr
->srcs
[srcidx
] = srcs
[srcidx
];
412 static snd_pcm_sframes_t
route_transfer(struct snd_pcm_plugin
*plugin
,
413 const struct snd_pcm_plugin_channel
*src_channels
,
414 struct snd_pcm_plugin_channel
*dst_channels
,
415 snd_pcm_uframes_t frames
)
417 struct route_priv
*data
;
418 int src_nchannels
, dst_nchannels
;
420 struct ttable_dst
*ttp
;
421 struct snd_pcm_plugin_channel
*dvp
;
423 snd_assert(plugin
!= NULL
&& src_channels
!= NULL
&& dst_channels
!= NULL
, return -ENXIO
);
426 data
= (struct route_priv
*)plugin
->extra_data
;
428 src_nchannels
= plugin
->src_format
.channels
;
429 dst_nchannels
= plugin
->dst_format
.channels
;
431 #ifdef CONFIG_SND_DEBUG
434 for (src_channel
= 0; src_channel
< src_nchannels
; ++src_channel
) {
435 snd_assert(src_channels
[src_channel
].area
.first
% 8 == 0 ||
436 src_channels
[src_channel
].area
.step
% 8 == 0,
439 for (dst_channel
= 0; dst_channel
< dst_nchannels
; ++dst_channel
) {
440 snd_assert(dst_channels
[dst_channel
].area
.first
% 8 == 0 ||
441 dst_channels
[dst_channel
].area
.step
% 8 == 0,
449 for (dst_channel
= 0; dst_channel
< dst_nchannels
; ++dst_channel
) {
450 ttp
->func(plugin
, src_channels
, dvp
, ttp
, frames
);
457 int getput_index(int format
)
459 int sign
, width
, endian
;
460 sign
= !snd_pcm_format_signed(format
);
461 width
= snd_pcm_format_width(format
) / 8 - 1;
462 if (width
< 0 || width
> 3) {
463 snd_printk(KERN_ERR
"snd-pcm-oss: invalid format %d\n", format
);
466 #ifdef SNDRV_LITTLE_ENDIAN
467 endian
= snd_pcm_format_big_endian(format
);
469 endian
= snd_pcm_format_little_endian(format
);
473 return width
* 4 + endian
* 2 + sign
;
476 int snd_pcm_plugin_build_route(struct snd_pcm_substream
*plug
,
477 struct snd_pcm_plugin_format
*src_format
,
478 struct snd_pcm_plugin_format
*dst_format
,
480 struct snd_pcm_plugin
**r_plugin
)
482 struct route_priv
*data
;
483 struct snd_pcm_plugin
*plugin
;
486 snd_assert(r_plugin
!= NULL
, return -ENXIO
);
488 snd_assert(src_format
->rate
== dst_format
->rate
, return -ENXIO
);
489 snd_assert(snd_pcm_format_linear(src_format
->format
) != 0 &&
490 snd_pcm_format_linear(dst_format
->format
) != 0,
493 err
= snd_pcm_plugin_build(plug
, "attenuated route conversion",
494 src_format
, dst_format
,
495 sizeof(struct route_priv
) +
496 sizeof(data
->ttable
[0]) * dst_format
->channels
,
501 data
= (struct route_priv
*)plugin
->extra_data
;
503 data
->get
= getput_index(src_format
->format
);
504 snd_assert(data
->get
>= 0 && data
->get
< 4*2*2, return -EINVAL
);
505 data
->put
= getput_index(dst_format
->format
);
506 snd_assert(data
->get
>= 0 && data
->get
< 4*2*2, return -EINVAL
);
507 data
->conv
= conv_index(src_format
->format
, dst_format
->format
);
509 if (snd_pcm_format_width(src_format
->format
) == 32)
510 data
->sum_type
= R_UINT64
;
512 data
->sum_type
= R_UINT32
;
513 data
->src_sample_size
= snd_pcm_format_width(src_format
->format
) / 8;
515 if ((err
= route_load_ttable(plugin
, ttable
)) < 0) {
516 snd_pcm_plugin_free(plugin
);
519 plugin
->transfer
= route_transfer
;
520 plugin
->src_channels_mask
= route_src_channels_mask
;
521 plugin
->dst_channels_mask
= route_dst_channels_mask
;