xref: /dflybsd-src/sys/dev/sound/pcm/feeder_volume.c (revision 2a1ad637466621af45d5a17185b33f3dcaaa1b1c)
1558a398bSSimon Schubert /*-
2*2a1ad637SFrançois Tigeot  * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
3558a398bSSimon Schubert  * All rights reserved.
4558a398bSSimon Schubert  *
5558a398bSSimon Schubert  * Redistribution and use in source and binary forms, with or without
6558a398bSSimon Schubert  * modification, are permitted provided that the following conditions
7558a398bSSimon Schubert  * are met:
8558a398bSSimon Schubert  * 1. Redistributions of source code must retain the above copyright
9558a398bSSimon Schubert  *    notice, this list of conditions and the following disclaimer.
10558a398bSSimon Schubert  * 2. Redistributions in binary form must reproduce the above copyright
11558a398bSSimon Schubert  *    notice, this list of conditions and the following disclaimer in the
12558a398bSSimon Schubert  *    documentation and/or other materials provided with the distribution.
13558a398bSSimon Schubert  *
14558a398bSSimon Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15558a398bSSimon Schubert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16558a398bSSimon Schubert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17558a398bSSimon Schubert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18558a398bSSimon Schubert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19558a398bSSimon Schubert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20558a398bSSimon Schubert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21558a398bSSimon Schubert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22558a398bSSimon Schubert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23558a398bSSimon Schubert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24558a398bSSimon Schubert  * SUCH DAMAGE.
25558a398bSSimon Schubert  */
26558a398bSSimon Schubert 
27*2a1ad637SFrançois Tigeot /* feeder_volume, a long 'Lost Technology' rather than a new feature. */
28*2a1ad637SFrançois Tigeot 
29*2a1ad637SFrançois Tigeot #ifdef _KERNEL
30*2a1ad637SFrançois Tigeot #ifdef HAVE_KERNEL_OPTION_HEADERS
31*2a1ad637SFrançois Tigeot #include "opt_snd.h"
32*2a1ad637SFrançois Tigeot #endif
33558a398bSSimon Schubert #include <dev/sound/pcm/sound.h>
34*2a1ad637SFrançois Tigeot #include <dev/sound/pcm/pcm.h>
35558a398bSSimon Schubert #include "feeder_if.h"
36558a398bSSimon Schubert 
37*2a1ad637SFrançois Tigeot #define SND_USE_FXDIV
38*2a1ad637SFrançois Tigeot #include "snd_fxdiv_gen.h"
39*2a1ad637SFrançois Tigeot 
40*2a1ad637SFrançois Tigeot SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/feeder_volume.c 193640 2009-06-07 19:12:08Z ariff $");
41*2a1ad637SFrançois Tigeot #endif
42*2a1ad637SFrançois Tigeot 
43*2a1ad637SFrançois Tigeot typedef void (*feed_volume_t)(int *, int *, uint32_t, uint8_t *, uint32_t);
44*2a1ad637SFrançois Tigeot 
45*2a1ad637SFrançois Tigeot #define FEEDVOLUME_CALC8(s, v)	(SND_VOL_CALC_SAMPLE((intpcm_t)		\
46*2a1ad637SFrançois Tigeot 				 (s) << 8, v) >> 8)
47*2a1ad637SFrançois Tigeot #define FEEDVOLUME_CALC16(s, v)	SND_VOL_CALC_SAMPLE((intpcm_t)(s), v)
48*2a1ad637SFrançois Tigeot #define FEEDVOLUME_CALC24(s, v)	SND_VOL_CALC_SAMPLE((intpcm64_t)(s), v)
49*2a1ad637SFrançois Tigeot #define FEEDVOLUME_CALC32(s, v)	SND_VOL_CALC_SAMPLE((intpcm64_t)(s), v)
50*2a1ad637SFrançois Tigeot 
51*2a1ad637SFrançois Tigeot #define FEEDVOLUME_DECLARE(SIGN, BIT, ENDIAN)				\
52*2a1ad637SFrançois Tigeot static void								\
53*2a1ad637SFrançois Tigeot feed_volume_##SIGN##BIT##ENDIAN(int *vol, int *matrix,			\
54*2a1ad637SFrançois Tigeot     uint32_t channels, uint8_t *dst, uint32_t count)			\
55*2a1ad637SFrançois Tigeot {									\
56*2a1ad637SFrançois Tigeot 	intpcm##BIT##_t v;						\
57*2a1ad637SFrançois Tigeot 	intpcm_t x;							\
58*2a1ad637SFrançois Tigeot 	uint32_t i;							\
59*2a1ad637SFrançois Tigeot 									\
60*2a1ad637SFrançois Tigeot 	dst += count * PCM_##BIT##_BPS * channels;			\
61*2a1ad637SFrançois Tigeot 	do {								\
62*2a1ad637SFrançois Tigeot 		i = channels;						\
63*2a1ad637SFrançois Tigeot 		do {							\
64*2a1ad637SFrançois Tigeot 			dst -= PCM_##BIT##_BPS;				\
65*2a1ad637SFrançois Tigeot 			i--;						\
66*2a1ad637SFrançois Tigeot 			x = PCM_READ_##SIGN##BIT##_##ENDIAN(dst);	\
67*2a1ad637SFrançois Tigeot 			v = FEEDVOLUME_CALC##BIT(x, vol[matrix[i]]);	\
68*2a1ad637SFrançois Tigeot 			x = PCM_CLAMP_##SIGN##BIT(v);			\
69*2a1ad637SFrançois Tigeot 			_PCM_WRITE_##SIGN##BIT##_##ENDIAN(dst, x);	\
70*2a1ad637SFrançois Tigeot 		} while (i != 0);					\
71*2a1ad637SFrançois Tigeot 	} while (--count != 0);						\
72*2a1ad637SFrançois Tigeot }
73*2a1ad637SFrançois Tigeot 
74*2a1ad637SFrançois Tigeot #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
75*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 16, LE)
76*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 32, LE)
77*2a1ad637SFrançois Tigeot #endif
78*2a1ad637SFrançois Tigeot #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
79*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 16, BE)
80*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 32, BE)
81*2a1ad637SFrançois Tigeot #endif
82*2a1ad637SFrançois Tigeot #ifdef SND_FEEDER_MULTIFORMAT
83*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S,  8, NE)
84*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 24, LE)
85*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(S, 24, BE)
86*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U,  8, NE)
87*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 16, LE)
88*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 24, LE)
89*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 32, LE)
90*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 16, BE)
91*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 24, BE)
92*2a1ad637SFrançois Tigeot FEEDVOLUME_DECLARE(U, 32, BE)
93*2a1ad637SFrançois Tigeot #endif
94*2a1ad637SFrançois Tigeot 
95*2a1ad637SFrançois Tigeot struct feed_volume_info {
96*2a1ad637SFrançois Tigeot 	uint32_t bps, channels;
97*2a1ad637SFrançois Tigeot 	feed_volume_t apply;
98*2a1ad637SFrançois Tigeot 	int volume_class;
99*2a1ad637SFrançois Tigeot 	int state;
100*2a1ad637SFrançois Tigeot 	int matrix[SND_CHN_MAX];
101*2a1ad637SFrançois Tigeot };
102*2a1ad637SFrançois Tigeot 
103*2a1ad637SFrançois Tigeot #define FEEDVOLUME_ENTRY(SIGN, BIT, ENDIAN)				\
104*2a1ad637SFrançois Tigeot 	{								\
105*2a1ad637SFrançois Tigeot 		AFMT_##SIGN##BIT##_##ENDIAN,				\
106*2a1ad637SFrançois Tigeot 		feed_volume_##SIGN##BIT##ENDIAN				\
107*2a1ad637SFrançois Tigeot 	}
108*2a1ad637SFrançois Tigeot 
109*2a1ad637SFrançois Tigeot static const struct {
110*2a1ad637SFrançois Tigeot 	uint32_t format;
111*2a1ad637SFrançois Tigeot 	feed_volume_t apply;
112*2a1ad637SFrançois Tigeot } feed_volume_info_tab[] = {
113*2a1ad637SFrançois Tigeot #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
114*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(S, 16, LE),
115*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(S, 32, LE),
116*2a1ad637SFrançois Tigeot #endif
117*2a1ad637SFrançois Tigeot #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT)
118*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(S, 16, BE),
119*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(S, 32, BE),
120*2a1ad637SFrançois Tigeot #endif
121*2a1ad637SFrançois Tigeot #ifdef SND_FEEDER_MULTIFORMAT
122*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(S,  8, NE),
123*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(S, 24, LE),
124*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(S, 24, BE),
125*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(U,  8, NE),
126*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(U, 16, LE),
127*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(U, 24, LE),
128*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(U, 32, LE),
129*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(U, 16, BE),
130*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(U, 24, BE),
131*2a1ad637SFrançois Tigeot 	FEEDVOLUME_ENTRY(U, 32, BE)
132*2a1ad637SFrançois Tigeot #endif
133*2a1ad637SFrançois Tigeot };
134*2a1ad637SFrançois Tigeot 
135*2a1ad637SFrançois Tigeot #define FEEDVOLUME_TAB_SIZE	((int32_t)				\
136*2a1ad637SFrançois Tigeot 				 (sizeof(feed_volume_info_tab) /	\
137*2a1ad637SFrançois Tigeot 				  sizeof(feed_volume_info_tab[0])))
138558a398bSSimon Schubert 
139558a398bSSimon Schubert static int
140*2a1ad637SFrançois Tigeot feed_volume_init(struct pcm_feeder *f)
141*2a1ad637SFrançois Tigeot {
142*2a1ad637SFrançois Tigeot 	struct feed_volume_info *info;
143*2a1ad637SFrançois Tigeot 	struct pcmchan_matrix *m;
144*2a1ad637SFrançois Tigeot 	uint32_t i;
145*2a1ad637SFrançois Tigeot 	int ret;
146*2a1ad637SFrançois Tigeot 
147*2a1ad637SFrançois Tigeot 	if (f->desc->in != f->desc->out ||
148*2a1ad637SFrançois Tigeot 	    AFMT_CHANNEL(f->desc->in) > SND_CHN_MAX)
149*2a1ad637SFrançois Tigeot 		return (EINVAL);
150*2a1ad637SFrançois Tigeot 
151*2a1ad637SFrançois Tigeot 	for (i = 0; i < FEEDVOLUME_TAB_SIZE; i++) {
152*2a1ad637SFrançois Tigeot 		if (AFMT_ENCODING(f->desc->in) ==
153*2a1ad637SFrançois Tigeot 		    feed_volume_info_tab[i].format) {
154*2a1ad637SFrançois Tigeot 			info = malloc(sizeof(*info), M_DEVBUF,
155*2a1ad637SFrançois Tigeot 			    M_NOWAIT | M_ZERO);
156*2a1ad637SFrançois Tigeot 			if (info == NULL)
157*2a1ad637SFrançois Tigeot 				return (ENOMEM);
158*2a1ad637SFrançois Tigeot 
159*2a1ad637SFrançois Tigeot 			info->bps = AFMT_BPS(f->desc->in);
160*2a1ad637SFrançois Tigeot 			info->channels = AFMT_CHANNEL(f->desc->in);
161*2a1ad637SFrançois Tigeot 			info->apply = feed_volume_info_tab[i].apply;
162*2a1ad637SFrançois Tigeot 			info->volume_class = SND_VOL_C_PCM;
163*2a1ad637SFrançois Tigeot 			info->state = FEEDVOLUME_ENABLE;
164*2a1ad637SFrançois Tigeot 
165*2a1ad637SFrançois Tigeot 			f->data = info;
166*2a1ad637SFrançois Tigeot 			m = feeder_matrix_default_channel_map(info->channels);
167*2a1ad637SFrançois Tigeot 			if (m == NULL) {
168*2a1ad637SFrançois Tigeot 				free(info, M_DEVBUF);
169*2a1ad637SFrançois Tigeot 				return (EINVAL);
170*2a1ad637SFrançois Tigeot 			}
171*2a1ad637SFrançois Tigeot 
172*2a1ad637SFrançois Tigeot 			ret = feeder_volume_apply_matrix(f, m);
173*2a1ad637SFrançois Tigeot 			if (ret != 0)
174*2a1ad637SFrançois Tigeot 				free(info, M_DEVBUF);
175*2a1ad637SFrançois Tigeot 
176*2a1ad637SFrançois Tigeot 			return (ret);
177*2a1ad637SFrançois Tigeot 		}
178*2a1ad637SFrançois Tigeot 	}
179*2a1ad637SFrançois Tigeot 
180*2a1ad637SFrançois Tigeot 	return (EINVAL);
181*2a1ad637SFrançois Tigeot }
182*2a1ad637SFrançois Tigeot 
183*2a1ad637SFrançois Tigeot static int
184*2a1ad637SFrançois Tigeot feed_volume_free(struct pcm_feeder *f)
185*2a1ad637SFrançois Tigeot {
186*2a1ad637SFrançois Tigeot 	struct feed_volume_info *info;
187*2a1ad637SFrançois Tigeot 
188*2a1ad637SFrançois Tigeot 	info = f->data;
189*2a1ad637SFrançois Tigeot 	if (info != NULL)
190*2a1ad637SFrançois Tigeot 		free(info, M_DEVBUF);
191*2a1ad637SFrançois Tigeot 
192*2a1ad637SFrançois Tigeot 	f->data = NULL;
193*2a1ad637SFrançois Tigeot 
194*2a1ad637SFrançois Tigeot 	return (0);
195*2a1ad637SFrançois Tigeot }
196*2a1ad637SFrançois Tigeot 
197*2a1ad637SFrançois Tigeot static int
198*2a1ad637SFrançois Tigeot feed_volume_set(struct pcm_feeder *f, int what, int value)
199*2a1ad637SFrançois Tigeot {
200*2a1ad637SFrançois Tigeot 	struct feed_volume_info *info;
201*2a1ad637SFrançois Tigeot 	struct pcmchan_matrix *m;
202*2a1ad637SFrançois Tigeot 	int ret;
203*2a1ad637SFrançois Tigeot 
204*2a1ad637SFrançois Tigeot 	info = f->data;
205*2a1ad637SFrançois Tigeot 	ret = 0;
206*2a1ad637SFrançois Tigeot 
207*2a1ad637SFrançois Tigeot 	switch (what) {
208*2a1ad637SFrançois Tigeot 	case FEEDVOLUME_CLASS:
209*2a1ad637SFrançois Tigeot 		if (value < SND_VOL_C_BEGIN || value > SND_VOL_C_END)
210*2a1ad637SFrançois Tigeot 			return (EINVAL);
211*2a1ad637SFrançois Tigeot 		info->volume_class = value;
212*2a1ad637SFrançois Tigeot 		break;
213*2a1ad637SFrançois Tigeot 	case FEEDVOLUME_CHANNELS:
214*2a1ad637SFrançois Tigeot 		if (value < SND_CHN_MIN || value > SND_CHN_MAX)
215*2a1ad637SFrançois Tigeot 			return (EINVAL);
216*2a1ad637SFrançois Tigeot 		m = feeder_matrix_default_channel_map(value);
217*2a1ad637SFrançois Tigeot 		if (m == NULL)
218*2a1ad637SFrançois Tigeot 			return (EINVAL);
219*2a1ad637SFrançois Tigeot 		ret = feeder_volume_apply_matrix(f, m);
220*2a1ad637SFrançois Tigeot 		break;
221*2a1ad637SFrançois Tigeot 	case FEEDVOLUME_STATE:
222*2a1ad637SFrançois Tigeot 		if (!(value == FEEDVOLUME_ENABLE || value == FEEDVOLUME_BYPASS))
223*2a1ad637SFrançois Tigeot 			return (EINVAL);
224*2a1ad637SFrançois Tigeot 		info->state = value;
225*2a1ad637SFrançois Tigeot 		break;
226*2a1ad637SFrançois Tigeot 	default:
227*2a1ad637SFrançois Tigeot 		return (EINVAL);
228*2a1ad637SFrançois Tigeot 		break;
229*2a1ad637SFrançois Tigeot 	}
230*2a1ad637SFrançois Tigeot 
231*2a1ad637SFrançois Tigeot 	return (ret);
232*2a1ad637SFrançois Tigeot }
233*2a1ad637SFrançois Tigeot 
234*2a1ad637SFrançois Tigeot static int
235*2a1ad637SFrançois Tigeot feed_volume_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
236558a398bSSimon Schubert     uint32_t count, void *source)
237558a398bSSimon Schubert {
238*2a1ad637SFrançois Tigeot 	struct feed_volume_info *info;
239*2a1ad637SFrançois Tigeot 	uint32_t j, align;
240*2a1ad637SFrançois Tigeot 	int i, *vol, *matrix;
241*2a1ad637SFrançois Tigeot 	uint8_t *dst;
242558a398bSSimon Schubert 
243*2a1ad637SFrançois Tigeot 	/*
244*2a1ad637SFrançois Tigeot 	 * Fetch filter data operation.
245*2a1ad637SFrançois Tigeot 	 */
246*2a1ad637SFrançois Tigeot 	info = f->data;
247*2a1ad637SFrançois Tigeot 
248*2a1ad637SFrançois Tigeot 	if (info->state == FEEDVOLUME_BYPASS)
249*2a1ad637SFrançois Tigeot 		return (FEEDER_FEED(f->source, c, b, count, source));
250*2a1ad637SFrançois Tigeot 
251*2a1ad637SFrançois Tigeot 	vol = c->volume[SND_VOL_C_VAL(info->volume_class)];
252*2a1ad637SFrançois Tigeot 	matrix = info->matrix;
253*2a1ad637SFrançois Tigeot 
254*2a1ad637SFrançois Tigeot 	/*
255*2a1ad637SFrançois Tigeot 	 * First, let see if we really need to apply gain at all.
256*2a1ad637SFrançois Tigeot 	 */
257*2a1ad637SFrançois Tigeot 	j = 0;
258*2a1ad637SFrançois Tigeot 	i = info->channels;
259*2a1ad637SFrançois Tigeot 	do {
260*2a1ad637SFrançois Tigeot 		if (vol[matrix[--i]] != SND_VOL_FLAT) {
261*2a1ad637SFrançois Tigeot 			j = 1;
262*2a1ad637SFrançois Tigeot 			break;
263558a398bSSimon Schubert 		}
264*2a1ad637SFrançois Tigeot 	} while (i != 0);
265*2a1ad637SFrançois Tigeot 
266*2a1ad637SFrançois Tigeot 	/* Nope, just bypass entirely. */
267*2a1ad637SFrançois Tigeot 	if (j == 0)
268*2a1ad637SFrançois Tigeot 		return (FEEDER_FEED(f->source, c, b, count, source));
269*2a1ad637SFrançois Tigeot 
270*2a1ad637SFrançois Tigeot 	dst = b;
271*2a1ad637SFrançois Tigeot 	align = info->bps * info->channels;
272*2a1ad637SFrançois Tigeot 
273*2a1ad637SFrançois Tigeot 	do {
274*2a1ad637SFrançois Tigeot 		if (count < align)
275*2a1ad637SFrançois Tigeot 			break;
276*2a1ad637SFrançois Tigeot 
277*2a1ad637SFrançois Tigeot 		j = SND_FXDIV(FEEDER_FEED(f->source, c, dst, count, source),
278*2a1ad637SFrançois Tigeot 		    align);
279*2a1ad637SFrançois Tigeot 		if (j == 0)
280*2a1ad637SFrançois Tigeot 			break;
281*2a1ad637SFrançois Tigeot 
282*2a1ad637SFrançois Tigeot 		info->apply(vol, matrix, info->channels, dst, j);
283*2a1ad637SFrançois Tigeot 
284*2a1ad637SFrançois Tigeot 		j *= align;
285*2a1ad637SFrançois Tigeot 		dst += j;
286*2a1ad637SFrançois Tigeot 		count -= j;
287*2a1ad637SFrançois Tigeot 
288*2a1ad637SFrançois Tigeot 	} while (count != 0);
289*2a1ad637SFrançois Tigeot 
290*2a1ad637SFrançois Tigeot 	return (dst - b);
291558a398bSSimon Schubert }
292558a398bSSimon Schubert 
293*2a1ad637SFrançois Tigeot static struct pcm_feederdesc feeder_volume_desc[] = {
294*2a1ad637SFrançois Tigeot 	{ FEEDER_VOLUME, 0, 0, 0, 0 },
295*2a1ad637SFrançois Tigeot 	{ 0, 0, 0, 0, 0 }
296558a398bSSimon Schubert };
297*2a1ad637SFrançois Tigeot 
298*2a1ad637SFrançois Tigeot static kobj_method_t feeder_volume_methods[] = {
299*2a1ad637SFrançois Tigeot 	KOBJMETHOD(feeder_init,		feed_volume_init),
300*2a1ad637SFrançois Tigeot 	KOBJMETHOD(feeder_free,		feed_volume_free),
301*2a1ad637SFrançois Tigeot 	KOBJMETHOD(feeder_set,		feed_volume_set),
302*2a1ad637SFrançois Tigeot 	KOBJMETHOD(feeder_feed,		feed_volume_feed),
3037774cda2SSascha Wildner 	KOBJMETHOD_END
304558a398bSSimon Schubert };
305*2a1ad637SFrançois Tigeot 
306*2a1ad637SFrançois Tigeot FEEDER_DECLARE(feeder_volume, NULL);
307*2a1ad637SFrançois Tigeot 
308*2a1ad637SFrançois Tigeot /* Extern */
309*2a1ad637SFrançois Tigeot 
310*2a1ad637SFrançois Tigeot /*
311*2a1ad637SFrançois Tigeot  * feeder_volume_apply_matrix(): For given matrix map, apply its configuration
312*2a1ad637SFrançois Tigeot  *                               to feeder_volume matrix structure. There are
313*2a1ad637SFrançois Tigeot  *                               possibilites that feeder_volume be inserted
314*2a1ad637SFrançois Tigeot  *                               before or after feeder_matrix, which in this
315*2a1ad637SFrançois Tigeot  *                               case feeder_volume must be in a good terms
316*2a1ad637SFrançois Tigeot  *                               with _current_ matrix.
317*2a1ad637SFrançois Tigeot  */
318*2a1ad637SFrançois Tigeot int
319*2a1ad637SFrançois Tigeot feeder_volume_apply_matrix(struct pcm_feeder *f, struct pcmchan_matrix *m)
320*2a1ad637SFrançois Tigeot {
321*2a1ad637SFrançois Tigeot 	struct feed_volume_info *info;
322*2a1ad637SFrançois Tigeot 	uint32_t i;
323*2a1ad637SFrançois Tigeot 
324*2a1ad637SFrançois Tigeot 	if (f == NULL || f->desc == NULL || f->desc->type != FEEDER_VOLUME ||
325*2a1ad637SFrançois Tigeot 	    f->data == NULL || m == NULL || m->channels < SND_CHN_MIN ||
326*2a1ad637SFrançois Tigeot 	    m->channels > SND_CHN_MAX)
327*2a1ad637SFrançois Tigeot 		return (EINVAL);
328*2a1ad637SFrançois Tigeot 
329*2a1ad637SFrançois Tigeot 	info = f->data;
330*2a1ad637SFrançois Tigeot 
331*2a1ad637SFrançois Tigeot 	for (i = 0; i < (sizeof(info->matrix) / sizeof(info->matrix[0])); i++) {
332*2a1ad637SFrançois Tigeot 		if (i < m->channels)
333*2a1ad637SFrançois Tigeot 			info->matrix[i] = m->map[i].type;
334*2a1ad637SFrançois Tigeot 		else
335*2a1ad637SFrançois Tigeot 			info->matrix[i] = SND_CHN_T_FL;
336*2a1ad637SFrançois Tigeot 	}
337*2a1ad637SFrançois Tigeot 
338*2a1ad637SFrançois Tigeot 	info->channels = m->channels;
339*2a1ad637SFrançois Tigeot 
340*2a1ad637SFrançois Tigeot 	return (0);
341*2a1ad637SFrançois Tigeot }
342