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>
23 #include <linux/slab.h>
24 #include <linux/time.h>
25 #include <sound/core.h>
26 #include <sound/pcm.h>
27 #include "pcm_plugin.h"
29 /* The best possible hack to support missing optimization in gcc 2.7.2.3 */
30 #if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0
31 #define div(a) a /= ROUTE_PLUGIN_RESOLUTION
32 #elif ROUTE_PLUGIN_RESOLUTION == 16
33 #define div(a) a >>= 4
35 #error "Add some code here"
38 typedef struct ttable_dst ttable_dst_t
;
39 typedef struct route_private_data route_t
;
41 typedef void (*route_channel_f
)(snd_pcm_plugin_t
*plugin
,
42 const snd_pcm_plugin_channel_t
*src_channels
,
43 snd_pcm_plugin_channel_t
*dst_channel
,
44 ttable_dst_t
* ttable
, snd_pcm_uframes_t frames
);
52 int att
; /* Attenuated */
58 struct route_private_data
{
59 enum {R_UINT32
=0, R_UINT64
=1} sum_type
;
63 ttable_dst_t ttable
[0];
72 static void route_to_channel_from_zero(snd_pcm_plugin_t
*plugin
,
73 const snd_pcm_plugin_channel_t
*src_channels ATTRIBUTE_UNUSED
,
74 snd_pcm_plugin_channel_t
*dst_channel
,
75 ttable_dst_t
* ttable ATTRIBUTE_UNUSED
, snd_pcm_uframes_t frames
)
77 if (dst_channel
->wanted
)
78 snd_pcm_area_silence(&dst_channel
->area
, 0, frames
, plugin
->dst_format
.format
);
79 dst_channel
->enabled
= 0;
82 static void route_to_channel_from_one(snd_pcm_plugin_t
*plugin
,
83 const snd_pcm_plugin_channel_t
*src_channels
,
84 snd_pcm_plugin_channel_t
*dst_channel
,
85 ttable_dst_t
* ttable
, snd_pcm_uframes_t frames
)
88 #include "plugin_ops.h"
90 route_t
*data
= (route_t
*)plugin
->extra_data
;
92 const snd_pcm_plugin_channel_t
*src_channel
= NULL
;
95 int src_step
, dst_step
;
96 for (srcidx
= 0; srcidx
< ttable
->nsrcs
; ++srcidx
) {
97 src_channel
= &src_channels
[ttable
->srcs
[srcidx
].channel
];
98 if (src_channel
->area
.addr
!= NULL
)
101 if (srcidx
== ttable
->nsrcs
) {
102 route_to_channel_from_zero(plugin
, src_channels
, dst_channel
, ttable
, frames
);
106 dst_channel
->enabled
= 1;
107 conv
= conv_labels
[data
->conv
];
108 src
= src_channel
->area
.addr
+ src_channel
->area
.first
/ 8;
109 src_step
= src_channel
->area
.step
/ 8;
110 dst
= dst_channel
->area
.addr
+ dst_channel
->area
.first
/ 8;
111 dst_step
= dst_channel
->area
.step
/ 8;
112 while (frames
-- > 0) {
114 #define CONV_END after
115 #include "plugin_ops.h"
123 static void route_to_channel(snd_pcm_plugin_t
*plugin
,
124 const snd_pcm_plugin_channel_t
*src_channels
,
125 snd_pcm_plugin_channel_t
*dst_channel
,
126 ttable_dst_t
* ttable
, snd_pcm_uframes_t frames
)
129 #define PUT_U32_LABELS
130 #include "plugin_ops.h"
132 #undef PUT_U32_LABELS
133 static void *zero_labels
[2] = { &&zero_int32
, &&zero_int64
};
135 static void *add_labels
[2 * 2] = { &&add_int32_noatt
, &&add_int32_att
,
136 &&add_int64_noatt
, &&add_int64_att
,
138 /* sum_type att shift */
139 static void *norm_labels
[2 * 2 * 4] = { NULL
,
140 &&norm_int32_8_noatt
,
141 &&norm_int32_16_noatt
,
142 &&norm_int32_24_noatt
,
147 &&norm_int64_0_noatt
,
148 &&norm_int64_8_noatt
,
149 &&norm_int64_16_noatt
,
150 &&norm_int64_24_noatt
,
156 route_t
*data
= (route_t
*)plugin
->extra_data
;
157 void *zero
, *get
, *add
, *norm
, *put_u32
;
158 int nsrcs
= ttable
->nsrcs
;
162 int src_steps
[nsrcs
];
163 ttable_src_t src_tt
[nsrcs
];
164 u_int32_t sample
= 0;
165 int srcidx
, srcidx1
= 0;
166 for (srcidx
= 0; srcidx
< nsrcs
; ++srcidx
) {
167 const snd_pcm_plugin_channel_t
*src_channel
= &src_channels
[ttable
->srcs
[srcidx
].channel
];
168 if (!src_channel
->enabled
)
170 srcs
[srcidx1
] = src_channel
->area
.addr
+ src_channel
->area
.first
/ 8;
171 src_steps
[srcidx1
] = src_channel
->area
.step
/ 8;
172 src_tt
[srcidx1
] = ttable
->srcs
[srcidx
];
177 route_to_channel_from_zero(plugin
, src_channels
, dst_channel
, ttable
, frames
);
179 } else if (nsrcs
== 1 && src_tt
[0].as_int
== ROUTE_PLUGIN_RESOLUTION
) {
180 route_to_channel_from_one(plugin
, src_channels
, dst_channel
, ttable
, frames
);
184 dst_channel
->enabled
= 1;
185 zero
= zero_labels
[data
->sum_type
];
186 get
= get_u_labels
[data
->get
];
187 add
= add_labels
[data
->sum_type
* 2 + ttable
->att
];
188 norm
= norm_labels
[data
->sum_type
* 8 + ttable
->att
* 4 + 4 - data
->src_sample_size
];
189 put_u32
= put_u32_labels
[data
->put
];
190 dst
= dst_channel
->area
.addr
+ dst_channel
->area
.first
/ 8;
191 dst_step
= dst_channel
->area
.step
/ 8;
193 while (frames
-- > 0) {
194 ttable_src_t
*ttp
= src_tt
;
206 for (srcidx
= 0; srcidx
< nsrcs
; ++srcidx
) {
207 char *src
= srcs
[srcidx
];
211 #define GET_U_END after_get
212 #include "plugin_ops.h"
219 sum
.as_uint32
+= sample
* ttp
->as_int
;
223 sum
.as_uint32
+= sample
;
226 sum
.as_uint64
+= (u_int64_t
) sample
* ttp
->as_int
;
230 sum
.as_uint64
+= sample
;
233 srcs
[srcidx
] += src_steps
[srcidx
];
240 sum
.as_uint64
= sum
.as_uint32
;
248 sum
.as_uint64
= sum
.as_uint32
;
250 sum
.as_uint64
<<= 16;
255 sum
.as_uint64
= sum
.as_uint32
;
257 sum
.as_uint64
<<= 24;
262 sum
.as_uint64
= sum
.as_uint32
;
268 sum
.as_uint64
= sum
.as_uint32
;
270 sum
.as_uint64
<<= 16;
274 sum
.as_uint64
= sum
.as_uint32
;
276 sum
.as_uint64
<<= 24;
281 if (sum
.as_uint64
> (u_int32_t
)0xffffffff)
282 sample
= (u_int32_t
)0xffffffff;
284 sample
= sum
.as_uint64
;
291 #define PUT_U32_END after_put_u32
292 #include "plugin_ops.h"
300 static int route_src_channels_mask(snd_pcm_plugin_t
*plugin
,
302 bitset_t
**src_vmask
)
304 route_t
*data
= (route_t
*)plugin
->extra_data
;
305 int schannels
= plugin
->src_format
.channels
;
306 int dchannels
= plugin
->dst_format
.channels
;
307 bitset_t
*vmask
= plugin
->src_vmask
;
309 ttable_dst_t
*dp
= data
->ttable
;
310 bitset_zero(vmask
, schannels
);
311 for (channel
= 0; channel
< dchannels
; channel
++, dp
++) {
314 if (!bitset_get(dst_vmask
, channel
))
317 for (src
= 0; src
< dp
->nsrcs
; src
++, sp
++)
318 bitset_set(vmask
, sp
->channel
);
324 static int route_dst_channels_mask(snd_pcm_plugin_t
*plugin
,
326 bitset_t
**dst_vmask
)
328 route_t
*data
= (route_t
*)plugin
->extra_data
;
329 int dchannels
= plugin
->dst_format
.channels
;
330 bitset_t
*vmask
= plugin
->dst_vmask
;
332 ttable_dst_t
*dp
= data
->ttable
;
333 bitset_zero(vmask
, dchannels
);
334 for (channel
= 0; channel
< dchannels
; channel
++, dp
++) {
338 for (src
= 0; src
< dp
->nsrcs
; src
++, sp
++) {
339 if (bitset_get(src_vmask
, sp
->channel
)) {
340 bitset_set(vmask
, channel
);
349 static void route_free(snd_pcm_plugin_t
*plugin
)
351 route_t
*data
= (route_t
*)plugin
->extra_data
;
352 unsigned int dst_channel
;
353 for (dst_channel
= 0; dst_channel
< plugin
->dst_format
.channels
; ++dst_channel
) {
354 kfree(data
->ttable
[dst_channel
].srcs
);
358 static int route_load_ttable(snd_pcm_plugin_t
*plugin
,
359 const route_ttable_entry_t
* src_ttable
)
362 unsigned int src_channel
, dst_channel
;
363 const route_ttable_entry_t
*sptr
;
365 if (src_ttable
== NULL
)
367 data
= (route_t
*)plugin
->extra_data
;
370 plugin
->private_free
= route_free
;
371 for (dst_channel
= 0; dst_channel
< plugin
->dst_format
.channels
; ++dst_channel
) {
372 route_ttable_entry_t t
= 0;
375 ttable_src_t srcs
[plugin
->src_format
.channels
];
376 for (src_channel
= 0; src_channel
< plugin
->src_format
.channels
; ++src_channel
) {
377 snd_assert(*sptr
>= 0 || *sptr
<= FULL
, return -ENXIO
);
379 srcs
[nsrcs
].channel
= src_channel
;
380 srcs
[nsrcs
].as_int
= *sptr
;
391 dptr
->func
= route_to_channel_from_zero
;
392 else if (nsrcs
== 1 && !att
)
393 dptr
->func
= route_to_channel_from_one
;
395 dptr
->func
= route_to_channel
;
398 dptr
->srcs
= kcalloc(nsrcs
, sizeof(*srcs
), GFP_KERNEL
);
399 for(srcidx
= 0; srcidx
< nsrcs
; srcidx
++)
400 dptr
->srcs
[srcidx
] = srcs
[srcidx
];
408 static snd_pcm_sframes_t
route_transfer(snd_pcm_plugin_t
*plugin
,
409 const snd_pcm_plugin_channel_t
*src_channels
,
410 snd_pcm_plugin_channel_t
*dst_channels
,
411 snd_pcm_uframes_t frames
)
414 int src_nchannels
, dst_nchannels
;
417 snd_pcm_plugin_channel_t
*dvp
;
419 snd_assert(plugin
!= NULL
&& src_channels
!= NULL
&& dst_channels
!= NULL
, return -ENXIO
);
422 data
= (route_t
*)plugin
->extra_data
;
424 src_nchannels
= plugin
->src_format
.channels
;
425 dst_nchannels
= plugin
->dst_format
.channels
;
427 #ifdef CONFIG_SND_DEBUG
430 for (src_channel
= 0; src_channel
< src_nchannels
; ++src_channel
) {
431 snd_assert(src_channels
[src_channel
].area
.first
% 8 == 0 ||
432 src_channels
[src_channel
].area
.step
% 8 == 0,
435 for (dst_channel
= 0; dst_channel
< dst_nchannels
; ++dst_channel
) {
436 snd_assert(dst_channels
[dst_channel
].area
.first
% 8 == 0 ||
437 dst_channels
[dst_channel
].area
.step
% 8 == 0,
445 for (dst_channel
= 0; dst_channel
< dst_nchannels
; ++dst_channel
) {
446 ttp
->func(plugin
, src_channels
, dvp
, ttp
, frames
);
453 int getput_index(int format
)
455 int sign
, width
, endian
;
456 sign
= !snd_pcm_format_signed(format
);
457 width
= snd_pcm_format_width(format
) / 8 - 1;
458 if (width
< 0 || width
> 3) {
459 snd_printk(KERN_ERR
"snd-pcm-oss: invalid format %d\n", format
);
462 #ifdef SNDRV_LITTLE_ENDIAN
463 endian
= snd_pcm_format_big_endian(format
);
465 endian
= snd_pcm_format_little_endian(format
);
469 return width
* 4 + endian
* 2 + sign
;
472 int snd_pcm_plugin_build_route(snd_pcm_plug_t
*plug
,
473 snd_pcm_plugin_format_t
*src_format
,
474 snd_pcm_plugin_format_t
*dst_format
,
475 route_ttable_entry_t
*ttable
,
476 snd_pcm_plugin_t
**r_plugin
)
479 snd_pcm_plugin_t
*plugin
;
482 snd_assert(r_plugin
!= NULL
, return -ENXIO
);
484 snd_assert(src_format
->rate
== dst_format
->rate
, return -ENXIO
);
485 snd_assert(snd_pcm_format_linear(src_format
->format
) != 0 &&
486 snd_pcm_format_linear(dst_format
->format
) != 0,
489 err
= snd_pcm_plugin_build(plug
, "attenuated route conversion",
490 src_format
, dst_format
,
491 sizeof(route_t
) + sizeof(data
->ttable
[0]) * dst_format
->channels
,
496 data
= (route_t
*) plugin
->extra_data
;
498 data
->get
= getput_index(src_format
->format
);
499 snd_assert(data
->get
>= 0 && data
->get
< 4*2*2, return -EINVAL
);
500 data
->put
= getput_index(dst_format
->format
);
501 snd_assert(data
->get
>= 0 && data
->get
< 4*2*2, return -EINVAL
);
502 data
->conv
= conv_index(src_format
->format
, dst_format
->format
);
504 if (snd_pcm_format_width(src_format
->format
) == 32)
505 data
->sum_type
= R_UINT64
;
507 data
->sum_type
= R_UINT32
;
508 data
->src_sample_size
= snd_pcm_format_width(src_format
->format
) / 8;
510 if ((err
= route_load_ttable(plugin
, ttable
)) < 0) {
511 snd_pcm_plugin_free(plugin
);
514 plugin
->transfer
= route_transfer
;
515 plugin
->src_channels_mask
= route_src_channels_mask
;
516 plugin
->dst_channels_mask
= route_dst_channels_mask
;