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"
40 typedef void (*route_channel_f
)(struct snd_pcm_plugin
*plugin
,
41 const struct snd_pcm_plugin_channel
*src_channels
,
42 struct snd_pcm_plugin_channel
*dst_channel
,
43 struct ttable_dst
*ttable
, snd_pcm_uframes_t frames
);
51 int att
; /* Attenuated */
53 struct ttable_src
*srcs
;
58 enum {R_UINT32
=0, R_UINT64
=1} sum_type
;
62 struct ttable_dst ttable
[0];
71 static void route_to_channel_from_zero(struct snd_pcm_plugin
*plugin
,
72 const struct snd_pcm_plugin_channel
*src_channels
,
73 struct snd_pcm_plugin_channel
*dst_channel
,
74 struct ttable_dst
*ttable
,
75 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(struct snd_pcm_plugin
*plugin
,
83 const struct snd_pcm_plugin_channel
*src_channels
,
84 struct snd_pcm_plugin_channel
*dst_channel
,
85 struct ttable_dst
*ttable
,
86 snd_pcm_uframes_t frames
)
89 #include "plugin_ops.h"
91 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
93 const struct snd_pcm_plugin_channel
*src_channel
= NULL
;
96 int src_step
, dst_step
;
97 for (srcidx
= 0; srcidx
< ttable
->nsrcs
; ++srcidx
) {
98 src_channel
= &src_channels
[ttable
->srcs
[srcidx
].channel
];
99 if (src_channel
->area
.addr
!= NULL
)
102 if (srcidx
== ttable
->nsrcs
) {
103 route_to_channel_from_zero(plugin
, src_channels
, dst_channel
, ttable
, frames
);
107 dst_channel
->enabled
= 1;
108 conv
= conv_labels
[data
->conv
];
109 src
= src_channel
->area
.addr
+ src_channel
->area
.first
/ 8;
110 src_step
= src_channel
->area
.step
/ 8;
111 dst
= dst_channel
->area
.addr
+ dst_channel
->area
.first
/ 8;
112 dst_step
= dst_channel
->area
.step
/ 8;
113 while (frames
-- > 0) {
115 #define CONV_END after
116 #include "plugin_ops.h"
124 static void route_to_channel(struct snd_pcm_plugin
*plugin
,
125 const struct snd_pcm_plugin_channel
*src_channels
,
126 struct snd_pcm_plugin_channel
*dst_channel
,
127 struct ttable_dst
*ttable
, snd_pcm_uframes_t frames
)
130 #define PUT_U32_LABELS
131 #include "plugin_ops.h"
133 #undef PUT_U32_LABELS
134 static void *zero_labels
[2] = { &&zero_int32
, &&zero_int64
};
136 static void *add_labels
[2 * 2] = { &&add_int32_noatt
, &&add_int32_att
,
137 &&add_int64_noatt
, &&add_int64_att
,
139 /* sum_type att shift */
140 static void *norm_labels
[2 * 2 * 4] = { NULL
,
141 &&norm_int32_8_noatt
,
142 &&norm_int32_16_noatt
,
143 &&norm_int32_24_noatt
,
148 &&norm_int64_0_noatt
,
149 &&norm_int64_8_noatt
,
150 &&norm_int64_16_noatt
,
151 &&norm_int64_24_noatt
,
157 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
158 void *zero
, *get
, *add
, *norm
, *put_u32
;
159 int nsrcs
= ttable
->nsrcs
;
163 int src_steps
[nsrcs
];
164 struct ttable_src src_tt
[nsrcs
];
165 u_int32_t sample
= 0;
166 int srcidx
, srcidx1
= 0;
167 for (srcidx
= 0; srcidx
< nsrcs
; ++srcidx
) {
168 const struct snd_pcm_plugin_channel
*src_channel
= &src_channels
[ttable
->srcs
[srcidx
].channel
];
169 if (!src_channel
->enabled
)
171 srcs
[srcidx1
] = src_channel
->area
.addr
+ src_channel
->area
.first
/ 8;
172 src_steps
[srcidx1
] = src_channel
->area
.step
/ 8;
173 src_tt
[srcidx1
] = ttable
->srcs
[srcidx
];
178 route_to_channel_from_zero(plugin
, src_channels
, dst_channel
, ttable
, frames
);
180 } else if (nsrcs
== 1 && src_tt
[0].as_int
== ROUTE_PLUGIN_RESOLUTION
) {
181 route_to_channel_from_one(plugin
, src_channels
, dst_channel
, ttable
, frames
);
185 dst_channel
->enabled
= 1;
186 zero
= zero_labels
[data
->sum_type
];
187 get
= get_u_labels
[data
->get
];
188 add
= add_labels
[data
->sum_type
* 2 + ttable
->att
];
189 norm
= norm_labels
[data
->sum_type
* 8 + ttable
->att
* 4 + 4 - data
->src_sample_size
];
190 put_u32
= put_u32_labels
[data
->put
];
191 dst
= dst_channel
->area
.addr
+ dst_channel
->area
.first
/ 8;
192 dst_step
= dst_channel
->area
.step
/ 8;
194 while (frames
-- > 0) {
195 struct ttable_src
*ttp
= src_tt
;
207 for (srcidx
= 0; srcidx
< nsrcs
; ++srcidx
) {
208 char *src
= srcs
[srcidx
];
212 #define GET_U_END after_get
213 #include "plugin_ops.h"
220 sum
.as_uint32
+= sample
* ttp
->as_int
;
224 sum
.as_uint32
+= sample
;
227 sum
.as_uint64
+= (u_int64_t
) sample
* ttp
->as_int
;
231 sum
.as_uint64
+= sample
;
234 srcs
[srcidx
] += src_steps
[srcidx
];
241 sum
.as_uint64
= sum
.as_uint32
;
249 sum
.as_uint64
= sum
.as_uint32
;
251 sum
.as_uint64
<<= 16;
256 sum
.as_uint64
= sum
.as_uint32
;
258 sum
.as_uint64
<<= 24;
263 sum
.as_uint64
= sum
.as_uint32
;
269 sum
.as_uint64
= sum
.as_uint32
;
271 sum
.as_uint64
<<= 16;
275 sum
.as_uint64
= sum
.as_uint32
;
277 sum
.as_uint64
<<= 24;
282 if (sum
.as_uint64
> (u_int32_t
)0xffffffff)
283 sample
= (u_int32_t
)0xffffffff;
285 sample
= sum
.as_uint64
;
292 #define PUT_U32_END after_put_u32
293 #include "plugin_ops.h"
301 static int route_src_channels_mask(struct snd_pcm_plugin
*plugin
,
302 unsigned long *dst_vmask
,
303 unsigned long **src_vmask
)
305 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
306 int schannels
= plugin
->src_format
.channels
;
307 int dchannels
= plugin
->dst_format
.channels
;
308 unsigned long *vmask
= plugin
->src_vmask
;
310 struct ttable_dst
*dp
= data
->ttable
;
311 bitmap_zero(vmask
, schannels
);
312 for (channel
= 0; channel
< dchannels
; channel
++, dp
++) {
314 struct ttable_src
*sp
;
315 if (!test_bit(channel
, dst_vmask
))
318 for (src
= 0; src
< dp
->nsrcs
; src
++, sp
++)
319 set_bit(sp
->channel
, vmask
);
325 static int route_dst_channels_mask(struct snd_pcm_plugin
*plugin
,
326 unsigned long *src_vmask
,
327 unsigned long **dst_vmask
)
329 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
330 int dchannels
= plugin
->dst_format
.channels
;
331 unsigned long *vmask
= plugin
->dst_vmask
;
333 struct ttable_dst
*dp
= data
->ttable
;
334 bitmap_zero(vmask
, dchannels
);
335 for (channel
= 0; channel
< dchannels
; channel
++, dp
++) {
337 struct ttable_src
*sp
;
339 for (src
= 0; src
< dp
->nsrcs
; src
++, sp
++) {
340 if (test_bit(sp
->channel
, src_vmask
)) {
341 set_bit(channel
, vmask
);
350 static void route_free(struct snd_pcm_plugin
*plugin
)
352 struct route_priv
*data
= (struct route_priv
*)plugin
->extra_data
;
353 unsigned int dst_channel
;
354 for (dst_channel
= 0; dst_channel
< plugin
->dst_format
.channels
; ++dst_channel
) {
355 kfree(data
->ttable
[dst_channel
].srcs
);
359 static int route_load_ttable(struct snd_pcm_plugin
*plugin
,
360 const int *src_ttable
)
362 struct route_priv
*data
;
363 unsigned int src_channel
, dst_channel
;
365 struct ttable_dst
*dptr
;
366 if (src_ttable
== NULL
)
368 data
= (struct route_priv
*)plugin
->extra_data
;
371 plugin
->private_free
= route_free
;
372 for (dst_channel
= 0; dst_channel
< plugin
->dst_format
.channels
; ++dst_channel
) {
376 struct ttable_src srcs
[plugin
->src_format
.channels
];
377 for (src_channel
= 0; src_channel
< plugin
->src_format
.channels
; ++src_channel
) {
378 snd_assert(*sptr
>= 0 || *sptr
<= FULL
, return -ENXIO
);
380 srcs
[nsrcs
].channel
= src_channel
;
381 srcs
[nsrcs
].as_int
= *sptr
;
392 dptr
->func
= route_to_channel_from_zero
;
393 else if (nsrcs
== 1 && !att
)
394 dptr
->func
= route_to_channel_from_one
;
396 dptr
->func
= route_to_channel
;
399 dptr
->srcs
= kcalloc(nsrcs
, sizeof(*srcs
), GFP_KERNEL
);
400 for(srcidx
= 0; srcidx
< nsrcs
; srcidx
++)
401 dptr
->srcs
[srcidx
] = srcs
[srcidx
];
409 static snd_pcm_sframes_t
route_transfer(struct snd_pcm_plugin
*plugin
,
410 const struct snd_pcm_plugin_channel
*src_channels
,
411 struct snd_pcm_plugin_channel
*dst_channels
,
412 snd_pcm_uframes_t frames
)
414 struct route_priv
*data
;
415 int src_nchannels
, dst_nchannels
;
417 struct ttable_dst
*ttp
;
418 struct snd_pcm_plugin_channel
*dvp
;
420 snd_assert(plugin
!= NULL
&& src_channels
!= NULL
&& dst_channels
!= NULL
, return -ENXIO
);
423 data
= (struct route_priv
*)plugin
->extra_data
;
425 src_nchannels
= plugin
->src_format
.channels
;
426 dst_nchannels
= plugin
->dst_format
.channels
;
428 #ifdef CONFIG_SND_DEBUG
431 for (src_channel
= 0; src_channel
< src_nchannels
; ++src_channel
) {
432 snd_assert(src_channels
[src_channel
].area
.first
% 8 == 0 ||
433 src_channels
[src_channel
].area
.step
% 8 == 0,
436 for (dst_channel
= 0; dst_channel
< dst_nchannels
; ++dst_channel
) {
437 snd_assert(dst_channels
[dst_channel
].area
.first
% 8 == 0 ||
438 dst_channels
[dst_channel
].area
.step
% 8 == 0,
446 for (dst_channel
= 0; dst_channel
< dst_nchannels
; ++dst_channel
) {
447 ttp
->func(plugin
, src_channels
, dvp
, ttp
, frames
);
454 int getput_index(int format
)
456 int sign
, width
, endian
;
457 sign
= !snd_pcm_format_signed(format
);
458 width
= snd_pcm_format_width(format
) / 8 - 1;
459 if (width
< 0 || width
> 3) {
460 snd_printk(KERN_ERR
"snd-pcm-oss: invalid format %d\n", format
);
463 #ifdef SNDRV_LITTLE_ENDIAN
464 endian
= snd_pcm_format_big_endian(format
);
466 endian
= snd_pcm_format_little_endian(format
);
470 return width
* 4 + endian
* 2 + sign
;
473 int snd_pcm_plugin_build_route(struct snd_pcm_substream
*plug
,
474 struct snd_pcm_plugin_format
*src_format
,
475 struct snd_pcm_plugin_format
*dst_format
,
477 struct snd_pcm_plugin
**r_plugin
)
479 struct route_priv
*data
;
480 struct snd_pcm_plugin
*plugin
;
483 snd_assert(r_plugin
!= NULL
, return -ENXIO
);
485 snd_assert(src_format
->rate
== dst_format
->rate
, return -ENXIO
);
486 snd_assert(snd_pcm_format_linear(src_format
->format
) != 0 &&
487 snd_pcm_format_linear(dst_format
->format
) != 0,
490 err
= snd_pcm_plugin_build(plug
, "attenuated route conversion",
491 src_format
, dst_format
,
492 sizeof(struct route_priv
) +
493 sizeof(data
->ttable
[0]) * dst_format
->channels
,
498 data
= (struct route_priv
*)plugin
->extra_data
;
500 data
->get
= getput_index(src_format
->format
);
501 snd_assert(data
->get
>= 0 && data
->get
< 4*2*2, return -EINVAL
);
502 data
->put
= getput_index(dst_format
->format
);
503 snd_assert(data
->get
>= 0 && data
->get
< 4*2*2, return -EINVAL
);
504 data
->conv
= conv_index(src_format
->format
, dst_format
->format
);
506 if (snd_pcm_format_width(src_format
->format
) == 32)
507 data
->sum_type
= R_UINT64
;
509 data
->sum_type
= R_UINT32
;
510 data
->src_sample_size
= snd_pcm_format_width(src_format
->format
) / 8;
512 if ((err
= route_load_ttable(plugin
, ttable
)) < 0) {
513 snd_pcm_plugin_free(plugin
);
516 plugin
->transfer
= route_transfer
;
517 plugin
->src_channels_mask
= route_src_channels_mask
;
518 plugin
->dst_channels_mask
= route_dst_channels_mask
;