1/**
2 * \file pcm/pcm_softvol.c
3 * \ingroup PCM_Plugins
4 * \brief PCM Soft Volume Plugin Interface
5 * \author Takashi Iwai <tiwai@suse.de>
6 * \date 2004
7 */
8/*
9 *  PCM - Soft Volume Plugin
10 *  Copyright (c) 2004 by Takashi Iwai <tiwai@suse.de>
11 *
12 *
13 *   This library is free software; you can redistribute it and/or modify
14 *   it under the terms of the GNU Lesser General Public License as
15 *   published by the Free Software Foundation; either version 2.1 of
16 *   the License, or (at your option) any later version.
17 *
18 *   This program is distributed in the hope that it will be useful,
19 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
20 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 *   GNU Lesser General Public License for more details.
22 *
23 *   You should have received a copy of the GNU Lesser General Public
24 *   License along with this library; if not, write to the Free Software
25 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
26 *
27 */
28
29#include <byteswap.h>
30#include <math.h>
31#include "pcm_local.h"
32#include "pcm_plugin.h"
33
34#ifndef PIC
35/* entry for static linking */
36const char *_snd_module_pcm_softvol = "";
37#endif
38
39#ifndef DOC_HIDDEN
40
41typedef struct {
42	/* This field need to be the first */
43	snd_pcm_plugin_t plug;
44	snd_pcm_format_t sformat;
45	unsigned int cchannels;
46	snd_ctl_t *ctl;
47	snd_ctl_elem_value_t elem;
48	unsigned int cur_vol[2];
49	unsigned int max_val;     /* max index */
50	unsigned int zero_dB_val; /* index at 0 dB */
51	double min_dB;
52	double max_dB;
53	unsigned int *dB_value;
54} snd_pcm_softvol_t;
55
56#define VOL_SCALE_SHIFT		16
57#define VOL_SCALE_MASK          ((1 << VOL_SCALE_SHIFT) - 1)
58
59#define PRESET_RESOLUTION	256
60#define PRESET_MIN_DB		-51.0
61#define ZERO_DB                  0.0
62#define MAX_DB_UPPER_LIMIT      50
63
64static const unsigned int preset_dB_value[PRESET_RESOLUTION] = {
65	0x00b8, 0x00bd, 0x00c1, 0x00c5, 0x00ca, 0x00cf, 0x00d4, 0x00d9,
66	0x00de, 0x00e3, 0x00e8, 0x00ed, 0x00f3, 0x00f9, 0x00fe, 0x0104,
67	0x010a, 0x0111, 0x0117, 0x011e, 0x0124, 0x012b, 0x0132, 0x0139,
68	0x0140, 0x0148, 0x0150, 0x0157, 0x015f, 0x0168, 0x0170, 0x0179,
69	0x0181, 0x018a, 0x0194, 0x019d, 0x01a7, 0x01b0, 0x01bb, 0x01c5,
70	0x01cf, 0x01da, 0x01e5, 0x01f1, 0x01fc, 0x0208, 0x0214, 0x0221,
71	0x022d, 0x023a, 0x0248, 0x0255, 0x0263, 0x0271, 0x0280, 0x028f,
72	0x029e, 0x02ae, 0x02be, 0x02ce, 0x02df, 0x02f0, 0x0301, 0x0313,
73	0x0326, 0x0339, 0x034c, 0x035f, 0x0374, 0x0388, 0x039d, 0x03b3,
74	0x03c9, 0x03df, 0x03f7, 0x040e, 0x0426, 0x043f, 0x0458, 0x0472,
75	0x048d, 0x04a8, 0x04c4, 0x04e0, 0x04fd, 0x051b, 0x053a, 0x0559,
76	0x0579, 0x0599, 0x05bb, 0x05dd, 0x0600, 0x0624, 0x0648, 0x066e,
77	0x0694, 0x06bb, 0x06e3, 0x070c, 0x0737, 0x0762, 0x078e, 0x07bb,
78	0x07e9, 0x0818, 0x0848, 0x087a, 0x08ac, 0x08e0, 0x0915, 0x094b,
79	0x0982, 0x09bb, 0x09f5, 0x0a30, 0x0a6d, 0x0aab, 0x0aeb, 0x0b2c,
80	0x0b6f, 0x0bb3, 0x0bf9, 0x0c40, 0x0c89, 0x0cd4, 0x0d21, 0x0d6f,
81	0x0dbf, 0x0e11, 0x0e65, 0x0ebb, 0x0f12, 0x0f6c, 0x0fc8, 0x1026,
82	0x1087, 0x10e9, 0x114e, 0x11b5, 0x121f, 0x128b, 0x12fa, 0x136b,
83	0x13df, 0x1455, 0x14ce, 0x154a, 0x15c9, 0x164b, 0x16d0, 0x1758,
84	0x17e4, 0x1872, 0x1904, 0x1999, 0x1a32, 0x1ace, 0x1b6e, 0x1c11,
85	0x1cb9, 0x1d64, 0x1e13, 0x1ec7, 0x1f7e, 0x203a, 0x20fa, 0x21bf,
86	0x2288, 0x2356, 0x2429, 0x2500, 0x25dd, 0x26bf, 0x27a6, 0x2892,
87	0x2984, 0x2a7c, 0x2b79, 0x2c7c, 0x2d85, 0x2e95, 0x2fab, 0x30c7,
88	0x31ea, 0x3313, 0x3444, 0x357c, 0x36bb, 0x3801, 0x394f, 0x3aa5,
89	0x3c02, 0x3d68, 0x3ed6, 0x404d, 0x41cd, 0x4355, 0x44e6, 0x4681,
90	0x4826, 0x49d4, 0x4b8c, 0x4d4f, 0x4f1c, 0x50f3, 0x52d6, 0x54c4,
91	0x56be, 0x58c3, 0x5ad4, 0x5cf2, 0x5f1c, 0x6153, 0x6398, 0x65e9,
92	0x6849, 0x6ab7, 0x6d33, 0x6fbf, 0x7259, 0x7503, 0x77bd, 0x7a87,
93	0x7d61, 0x804d, 0x834a, 0x8659, 0x897a, 0x8cae, 0x8ff5, 0x934f,
94	0x96bd, 0x9a40, 0x9dd8, 0xa185, 0xa548, 0xa922, 0xad13, 0xb11b,
95	0xb53b, 0xb973, 0xbdc5, 0xc231, 0xc6b7, 0xcb58, 0xd014, 0xd4ed,
96	0xd9e3, 0xdef6, 0xe428, 0xe978, 0xeee8, 0xf479, 0xfa2b, 0xffff,
97};
98
99/* (32bit x 16bit) >> 16 */
100typedef union {
101	int i;
102	short s[2];
103} val_t;
104static inline int MULTI_DIV_32x16(int a, unsigned short b)
105{
106	val_t v, x, y;
107	v.i = a;
108	y.i = 0;
109#if __BYTE_ORDER == __LITTLE_ENDIAN
110	x.i = (unsigned short)v.s[0];
111	x.i *= b;
112	y.s[0] = x.s[1];
113	y.i += (int)v.s[1] * b;
114#else
115	x.i = (unsigned int)v.s[1] * b;
116	y.s[1] = x.s[0];
117	y.i += (int)v.s[0] * b;
118#endif
119	return y.i;
120}
121
122static inline int MULTI_DIV_int(int a, unsigned int b, int swap)
123{
124	unsigned int gain = (b >> VOL_SCALE_SHIFT);
125	int fraction;
126	a = swap ? (int)bswap_32(a) : a;
127	fraction = MULTI_DIV_32x16(a, b & VOL_SCALE_MASK);
128	if (gain) {
129		long long amp = (long long)a * gain + fraction;
130		if (amp > (int)0x7fffffff)
131			amp = (int)0x7fffffff;
132		else if (amp < (int)0x80000000)
133			amp = (int)0x80000000;
134		return swap ? (int)bswap_32((int)amp) : (int)amp;
135	}
136	return swap ? (int)bswap_32(fraction) : fraction;
137}
138
139/* always little endian */
140static inline int MULTI_DIV_24(int a, unsigned int b)
141{
142	unsigned int gain = b >> VOL_SCALE_SHIFT;
143	int fraction;
144	fraction = MULTI_DIV_32x16(a, b & VOL_SCALE_MASK);
145	if (gain) {
146		long long amp = (long long)a * gain + fraction;
147		if (amp > (int)0x7fffff)
148			amp = (int)0x7fffff;
149		else if (amp < (int)0x800000)
150			amp = (int)0x800000;
151		return (int)amp;
152	}
153	return fraction;
154}
155
156static inline short MULTI_DIV_short(short a, unsigned int b, int swap)
157{
158	unsigned int gain = b >> VOL_SCALE_SHIFT;
159	int fraction;
160	a = swap ? (short)bswap_16(a) : a;
161	fraction = (int)(a * (b & VOL_SCALE_MASK)) >> VOL_SCALE_SHIFT;
162	if (gain) {
163		int amp = a * gain + fraction;
164		if (abs(amp) > 0x7fff)
165			amp = (a<0) ? (short)0x8000 : (short)0x7fff;
166		return swap ? (short)bswap_16((short)amp) : (short)amp;
167	}
168	return swap ? (short)bswap_16((short)fraction) : (short)fraction;
169}
170
171#endif /* DOC_HIDDEN */
172
173/*
174 * apply volumue attenuation
175 *
176 * TODO: use SIMD operations
177 */
178
179#ifndef DOC_HIDDEN
180#define CONVERT_AREA(TYPE, swap) do {	\
181	unsigned int ch, fr; \
182	TYPE *src, *dst; \
183	for (ch = 0; ch < channels; ch++) { \
184		src_area = &src_areas[ch]; \
185		dst_area = &dst_areas[ch]; \
186		src = snd_pcm_channel_area_addr(src_area, src_offset); \
187		dst = snd_pcm_channel_area_addr(dst_area, dst_offset); \
188		src_step = snd_pcm_channel_area_step(src_area) / sizeof(TYPE); \
189		dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(TYPE); \
190		GET_VOL_SCALE; \
191		fr = frames; \
192		if (! vol_scale) { \
193			while (fr--) { \
194				*dst = 0; \
195				dst += dst_step; \
196			} \
197		} else if (vol_scale == 0xffff) { \
198			while (fr--) { \
199				*dst = *src; \
200				src += src_step; \
201				dst += dst_step; \
202			} \
203		} else { \
204			while (fr--) { \
205				*dst = (TYPE) MULTI_DIV_##TYPE(*src, vol_scale, swap); \
206				src += src_step; \
207				dst += dst_step; \
208			} \
209		} \
210	} \
211} while (0)
212
213#define CONVERT_AREA_S24_3LE() do {					\
214	unsigned int ch, fr;						\
215	unsigned char *src, *dst;					\
216	int tmp;							\
217	for (ch = 0; ch < channels; ch++) {				\
218		src_area = &src_areas[ch];				\
219		dst_area = &dst_areas[ch];				\
220		src = snd_pcm_channel_area_addr(src_area, src_offset);	\
221		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);	\
222		src_step = snd_pcm_channel_area_step(src_area);		\
223		dst_step = snd_pcm_channel_area_step(dst_area);		\
224		GET_VOL_SCALE;						\
225		fr = frames;						\
226		if (! vol_scale) {					\
227			while (fr--) {					\
228				dst[0] = dst[1] = dst[2] = 0;		\
229				dst += dst_step;			\
230			}						\
231		} else if (vol_scale == 0xffff) {			\
232			while (fr--) {					\
233				dst[0] = src[0];			\
234				dst[1] = src[1];			\
235				dst[2] = src[2];			\
236				src += dst_step;			\
237				dst += src_step;			\
238			}						\
239		} else {						\
240			while (fr--) {					\
241				tmp = src[0] |				\
242				      (src[1] << 8) |			\
243				      (((signed char *) src)[2] << 16);	\
244				tmp = MULTI_DIV_24(tmp, vol_scale);	\
245				dst[0] = tmp;				\
246				dst[1] = tmp >> 8;			\
247				dst[2] = tmp >> 16;			\
248				src += dst_step;			\
249				dst += src_step;			\
250			}						\
251		}							\
252	}								\
253} while (0)
254
255#define GET_VOL_SCALE \
256	switch (ch) { \
257	case 0: \
258	case 2: \
259		vol_scale = (channels == ch + 1) ? vol_c : vol[0]; \
260		break; \
261	case 4: \
262	case 5: \
263		vol_scale = vol_c; \
264		break; \
265	default: \
266		vol_scale = vol[ch & 1]; \
267		break; \
268	}
269
270#endif /* DOC_HIDDEN */
271
272/* 2-channel stereo control */
273static void softvol_convert_stereo_vol(snd_pcm_softvol_t *svol,
274				       const snd_pcm_channel_area_t *dst_areas,
275				       snd_pcm_uframes_t dst_offset,
276				       const snd_pcm_channel_area_t *src_areas,
277				       snd_pcm_uframes_t src_offset,
278				       unsigned int channels,
279				       snd_pcm_uframes_t frames)
280{
281	const snd_pcm_channel_area_t *dst_area, *src_area;
282	unsigned int src_step, dst_step;
283	unsigned int vol_scale, vol[2], vol_c;
284
285	if (svol->cur_vol[0] == 0 && svol->cur_vol[1] == 0) {
286		snd_pcm_areas_silence(dst_areas, dst_offset, channels, frames,
287				      svol->sformat);
288		return;
289	} else if (svol->zero_dB_val && svol->cur_vol[0] == svol->zero_dB_val &&
290		   svol->cur_vol[1] == svol->zero_dB_val) {
291		snd_pcm_areas_copy(dst_areas, dst_offset, src_areas, src_offset,
292				   channels, frames, svol->sformat);
293		return;
294	}
295
296	if (svol->max_val == 1) {
297		vol[0] = svol->cur_vol[0] ? 0xffff : 0;
298		vol[1] = svol->cur_vol[1] ? 0xffff : 0;
299		vol_c = vol[0] | vol[1];
300	} else {
301		vol[0] = svol->dB_value[svol->cur_vol[0]];
302		vol[1] = svol->dB_value[svol->cur_vol[1]];
303		vol_c = svol->dB_value[(svol->cur_vol[0] + svol->cur_vol[1]) / 2];
304	}
305	switch (svol->sformat) {
306	case SND_PCM_FORMAT_S16_LE:
307	case SND_PCM_FORMAT_S16_BE:
308		/* 16bit samples */
309		CONVERT_AREA(short,
310			     !snd_pcm_format_cpu_endian(svol->sformat));
311		break;
312	case SND_PCM_FORMAT_S32_LE:
313	case SND_PCM_FORMAT_S32_BE:
314		/* 32bit samples */
315		CONVERT_AREA(int,
316			     !snd_pcm_format_cpu_endian(svol->sformat));
317		break;
318	case SND_PCM_FORMAT_S24_3LE:
319		CONVERT_AREA_S24_3LE();
320		break;
321	default:
322		break;
323	}
324}
325
326#undef GET_VOL_SCALE
327#define GET_VOL_SCALE
328
329/* mono control */
330static void softvol_convert_mono_vol(snd_pcm_softvol_t *svol,
331				     const snd_pcm_channel_area_t *dst_areas,
332				     snd_pcm_uframes_t dst_offset,
333				     const snd_pcm_channel_area_t *src_areas,
334				     snd_pcm_uframes_t src_offset,
335				     unsigned int channels,
336				     snd_pcm_uframes_t frames)
337{
338	const snd_pcm_channel_area_t *dst_area, *src_area;
339	unsigned int src_step, dst_step;
340	unsigned int vol_scale;
341
342	if (svol->cur_vol[0] == 0) {
343		snd_pcm_areas_silence(dst_areas, dst_offset, channels, frames,
344				      svol->sformat);
345		return;
346	} else if (svol->zero_dB_val && svol->cur_vol[0] == svol->zero_dB_val) {
347		snd_pcm_areas_copy(dst_areas, dst_offset, src_areas, src_offset,
348				   channels, frames, svol->sformat);
349		return;
350	}
351
352	if (svol->max_val == 1)
353		vol_scale = svol->cur_vol[0] ? 0xffff : 0;
354	else
355		vol_scale = svol->dB_value[svol->cur_vol[0]];
356	switch (svol->sformat) {
357	case SND_PCM_FORMAT_S16_LE:
358	case SND_PCM_FORMAT_S16_BE:
359		/* 16bit samples */
360		CONVERT_AREA(short,
361			     !snd_pcm_format_cpu_endian(svol->sformat));
362		break;
363	case SND_PCM_FORMAT_S32_LE:
364	case SND_PCM_FORMAT_S32_BE:
365		/* 32bit samples */
366		CONVERT_AREA(int,
367			     !snd_pcm_format_cpu_endian(svol->sformat));
368		break;
369	case SND_PCM_FORMAT_S24_3LE:
370		CONVERT_AREA_S24_3LE();
371		break;
372	default:
373		break;
374	}
375}
376
377/*
378 * get the current volume value from driver
379 *
380 * TODO: mmap support?
381 */
382static void get_current_volume(snd_pcm_softvol_t *svol)
383{
384	unsigned int val;
385	unsigned int i;
386
387	if (snd_ctl_elem_read(svol->ctl, &svol->elem) < 0)
388		return;
389	for (i = 0; i < svol->cchannels; i++) {
390		val = svol->elem.value.integer.value[i];
391		if (val > svol->max_val)
392			val = svol->max_val;
393		svol->cur_vol[i] = val;
394	}
395}
396
397static void softvol_free(snd_pcm_softvol_t *svol)
398{
399	if (svol->plug.gen.close_slave)
400		snd_pcm_close(svol->plug.gen.slave);
401	if (svol->ctl)
402		snd_ctl_close(svol->ctl);
403	if (svol->dB_value && svol->dB_value != preset_dB_value)
404		free(svol->dB_value);
405	free(svol);
406}
407
408static int snd_pcm_softvol_close(snd_pcm_t *pcm)
409{
410	snd_pcm_softvol_t *svol = pcm->private_data;
411	softvol_free(svol);
412	return 0;
413}
414
415static int snd_pcm_softvol_hw_refine_cprepare(snd_pcm_t *pcm,
416					      snd_pcm_hw_params_t *params)
417{
418	int err;
419	snd_pcm_softvol_t *svol = pcm->private_data;
420	snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
421	snd_pcm_format_mask_t format_mask = {
422		{
423			(1ULL << SND_PCM_FORMAT_S16_LE) |
424			(1ULL << SND_PCM_FORMAT_S16_BE) |
425			(1ULL << SND_PCM_FORMAT_S32_LE) |
426 			(1ULL << SND_PCM_FORMAT_S32_BE),
427			(1ULL << (SND_PCM_FORMAT_S24_3LE - 32))
428		}
429	};
430	if (svol->sformat != SND_PCM_FORMAT_UNKNOWN) {
431		snd_pcm_format_mask_none(&format_mask);
432		snd_pcm_format_mask_set(&format_mask, svol->sformat);
433	}
434	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
435					 &access_mask);
436	if (err < 0)
437		return err;
438	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
439					 &format_mask);
440	if (err < 0)
441		return err;
442	err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
443	if (err < 0)
444		return err;
445	err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0);
446	if (err < 0)
447		return err;
448	params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
449	return 0;
450}
451
452static int snd_pcm_softvol_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
453{
454	snd_pcm_softvol_t *svol = pcm->private_data;
455	snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
456	_snd_pcm_hw_params_any(sparams);
457	_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
458				   &saccess_mask);
459	if (svol->sformat != SND_PCM_FORMAT_UNKNOWN) {
460		_snd_pcm_hw_params_set_format(sparams, svol->sformat);
461		_snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
462	}
463	return 0;
464}
465
466/*
467 * refine the access mask
468 */
469static int check_access_mask(snd_pcm_hw_params_t *src,
470			     snd_pcm_hw_params_t *dst)
471{
472	const snd_pcm_access_mask_t *mask;
473	snd_pcm_access_mask_t smask;
474
475	mask = snd_pcm_hw_param_get_mask(src, SND_PCM_HW_PARAM_ACCESS);
476	snd_mask_none(&smask);
477	if (snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
478	    snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) {
479		snd_pcm_access_mask_set(&smask,
480					SND_PCM_ACCESS_RW_INTERLEAVED);
481		snd_pcm_access_mask_set(&smask,
482					SND_PCM_ACCESS_MMAP_INTERLEAVED);
483	}
484	if (snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) ||
485	    snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))  {
486		snd_pcm_access_mask_set(&smask,
487					SND_PCM_ACCESS_RW_NONINTERLEAVED);
488		snd_pcm_access_mask_set(&smask,
489					SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
490	}
491	if (snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_MMAP_COMPLEX))
492		snd_pcm_access_mask_set(&smask,
493					SND_PCM_ACCESS_MMAP_COMPLEX);
494
495	return _snd_pcm_hw_param_set_mask(dst, SND_PCM_HW_PARAM_ACCESS, &smask);
496}
497
498static int snd_pcm_softvol_hw_refine_schange(snd_pcm_t *pcm,
499					     snd_pcm_hw_params_t *params,
500					     snd_pcm_hw_params_t *sparams)
501{
502	snd_pcm_softvol_t *svol = pcm->private_data;
503	int err;
504	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
505			      SND_PCM_HW_PARBIT_RATE |
506			      SND_PCM_HW_PARBIT_PERIODS |
507			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
508			      SND_PCM_HW_PARBIT_PERIOD_TIME |
509			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
510			      SND_PCM_HW_PARBIT_BUFFER_TIME |
511			      SND_PCM_HW_PARBIT_TICK_TIME);
512	if (svol->sformat == SND_PCM_FORMAT_UNKNOWN)
513		links |= (SND_PCM_HW_PARBIT_FORMAT |
514			  SND_PCM_HW_PARBIT_SUBFORMAT |
515			  SND_PCM_HW_PARBIT_SAMPLE_BITS);
516	err = _snd_pcm_hw_params_refine(sparams, links, params);
517	if (err < 0)
518		return err;
519
520	err = check_access_mask(params, sparams);
521	if (err < 0)
522		return err;
523
524	return 0;
525}
526
527static int snd_pcm_softvol_hw_refine_cchange(snd_pcm_t *pcm,
528					     snd_pcm_hw_params_t *params,
529					    snd_pcm_hw_params_t *sparams)
530{
531	snd_pcm_softvol_t *svol = pcm->private_data;
532	int err;
533	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
534			      SND_PCM_HW_PARBIT_RATE |
535			      SND_PCM_HW_PARBIT_PERIODS |
536			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
537			      SND_PCM_HW_PARBIT_PERIOD_TIME |
538			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
539			      SND_PCM_HW_PARBIT_BUFFER_TIME |
540			      SND_PCM_HW_PARBIT_TICK_TIME);
541	if (svol->sformat == SND_PCM_FORMAT_UNKNOWN)
542		links |= (SND_PCM_HW_PARBIT_FORMAT |
543			  SND_PCM_HW_PARBIT_SUBFORMAT |
544			  SND_PCM_HW_PARBIT_SAMPLE_BITS);
545	err = _snd_pcm_hw_params_refine(params, links, sparams);
546	if (err < 0)
547		return err;
548
549	err = check_access_mask(sparams, params);
550	if (err < 0)
551		return err;
552
553	return 0;
554}
555
556static int snd_pcm_softvol_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
557{
558	return snd_pcm_hw_refine_slave(pcm, params,
559				       snd_pcm_softvol_hw_refine_cprepare,
560				       snd_pcm_softvol_hw_refine_cchange,
561				       snd_pcm_softvol_hw_refine_sprepare,
562				       snd_pcm_softvol_hw_refine_schange,
563				       snd_pcm_generic_hw_refine);
564}
565
566static int snd_pcm_softvol_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
567{
568	snd_pcm_softvol_t *svol = pcm->private_data;
569	snd_pcm_t *slave = svol->plug.gen.slave;
570	int err = snd_pcm_hw_params_slave(pcm, params,
571					  snd_pcm_softvol_hw_refine_cchange,
572					  snd_pcm_softvol_hw_refine_sprepare,
573					  snd_pcm_softvol_hw_refine_schange,
574					  snd_pcm_generic_hw_params);
575	if (err < 0)
576		return err;
577	if (slave->format != SND_PCM_FORMAT_S16_LE &&
578	    slave->format != SND_PCM_FORMAT_S16_BE &&
579	    slave->format != SND_PCM_FORMAT_S24_3LE &&
580	    slave->format != SND_PCM_FORMAT_S32_LE &&
581	    slave->format != SND_PCM_FORMAT_S32_BE) {
582		SNDERR("softvol supports only S16_LE, S16_BE, S24_3LE, S32_LE "
583		       " or S32_BE");
584		return -EINVAL;
585	}
586	svol->sformat = slave->format;
587	return 0;
588}
589
590static snd_pcm_uframes_t
591snd_pcm_softvol_write_areas(snd_pcm_t *pcm,
592			    const snd_pcm_channel_area_t *areas,
593			    snd_pcm_uframes_t offset,
594			    snd_pcm_uframes_t size,
595			    const snd_pcm_channel_area_t *slave_areas,
596			    snd_pcm_uframes_t slave_offset,
597			    snd_pcm_uframes_t *slave_sizep)
598{
599	snd_pcm_softvol_t *svol = pcm->private_data;
600	if (size > *slave_sizep)
601		size = *slave_sizep;
602	get_current_volume(svol);
603	if (svol->cchannels == 1)
604		softvol_convert_mono_vol(svol, slave_areas, slave_offset,
605					 areas, offset, pcm->channels, size);
606	else
607		softvol_convert_stereo_vol(svol, slave_areas, slave_offset,
608					   areas, offset, pcm->channels, size);
609	*slave_sizep = size;
610	return size;
611}
612
613static snd_pcm_uframes_t
614snd_pcm_softvol_read_areas(snd_pcm_t *pcm,
615			   const snd_pcm_channel_area_t *areas,
616			   snd_pcm_uframes_t offset,
617			   snd_pcm_uframes_t size,
618			   const snd_pcm_channel_area_t *slave_areas,
619			   snd_pcm_uframes_t slave_offset,
620			   snd_pcm_uframes_t *slave_sizep)
621{
622	snd_pcm_softvol_t *svol = pcm->private_data;
623	if (size > *slave_sizep)
624		size = *slave_sizep;
625	get_current_volume(svol);
626	if (svol->cchannels == 1)
627		softvol_convert_mono_vol(svol, areas, offset, slave_areas,
628					 slave_offset, pcm->channels, size);
629	else
630		softvol_convert_stereo_vol(svol, areas, offset, slave_areas,
631					   slave_offset, pcm->channels, size);
632	*slave_sizep = size;
633	return size;
634}
635
636static void snd_pcm_softvol_dump(snd_pcm_t *pcm, snd_output_t *out)
637{
638	snd_pcm_softvol_t *svol = pcm->private_data;
639	snd_output_printf(out, "Soft volume PCM\n");
640	snd_output_printf(out, "Control: %s\n", svol->elem.id.name);
641	if (svol->max_val == 1)
642		snd_output_printf(out, "boolean\n");
643	else {
644		snd_output_printf(out, "min_dB: %g\n", svol->min_dB);
645		snd_output_printf(out, "max_dB: %g\n", svol->max_dB);
646		snd_output_printf(out, "resolution: %d\n", svol->max_val + 1);
647	}
648	if (pcm->setup) {
649		snd_output_printf(out, "Its setup is:\n");
650		snd_pcm_dump_setup(pcm, out);
651	}
652	snd_output_printf(out, "Slave: ");
653	snd_pcm_dump(svol->plug.gen.slave, out);
654}
655
656static int add_tlv_info(snd_pcm_softvol_t *svol, snd_ctl_elem_info_t *cinfo)
657{
658	unsigned int tlv[4];
659	tlv[0] = SND_CTL_TLVT_DB_SCALE;
660	tlv[1] = 2 * sizeof(int);
661	tlv[2] = svol->min_dB * 100;
662	tlv[3] = (svol->max_dB - svol->min_dB) * 100 / svol->max_val;
663	return snd_ctl_elem_tlv_write(svol->ctl, &cinfo->id, tlv);
664}
665
666static int add_user_ctl(snd_pcm_softvol_t *svol, snd_ctl_elem_info_t *cinfo, int count)
667{
668	int err;
669	int i;
670	unsigned int def_val;
671
672	if (svol->max_val == 1)
673		err = snd_ctl_elem_add_boolean(svol->ctl, &cinfo->id, count);
674	else
675		err = snd_ctl_elem_add_integer(svol->ctl, &cinfo->id, count,
676					       0, svol->max_val, 0);
677	if (err < 0)
678		return err;
679	if (svol->max_val == 1)
680		def_val = 1;
681	else {
682		add_tlv_info(svol, cinfo);
683		/* set zero dB value as default, or max_val if
684		   there is no 0 dB setting */
685		def_val = svol->zero_dB_val ? svol->zero_dB_val : svol->max_val;
686	}
687	for (i = 0; i < count; i++)
688		svol->elem.value.integer.value[i] = def_val;
689	return snd_ctl_elem_write(svol->ctl, &svol->elem);
690}
691
692/*
693 * load and set up user-control
694 * returns 0 if the user-control is found or created,
695 * returns 1 if the control is a hw control,
696 * or a negative error code
697 */
698static int softvol_load_control(snd_pcm_t *pcm, snd_pcm_softvol_t *svol,
699				int ctl_card, snd_ctl_elem_id_t *ctl_id,
700				int cchannels, double min_dB, double max_dB,
701				int resolution)
702{
703	char tmp_name[32];
704	snd_pcm_info_t *info;
705	snd_ctl_elem_info_t *cinfo;
706	int err;
707	unsigned int i;
708
709	if (ctl_card < 0) {
710		snd_pcm_info_alloca(&info);
711		err = snd_pcm_info(pcm, info);
712		if (err < 0)
713			return err;
714		ctl_card = snd_pcm_info_get_card(info);
715		if (ctl_card < 0) {
716			SNDERR("No card defined for softvol control");
717			return -EINVAL;
718		}
719	}
720	sprintf(tmp_name, "hw:%d", ctl_card);
721	err = snd_ctl_open(&svol->ctl, tmp_name, 0);
722	if (err < 0) {
723		SNDERR("Cannot open CTL %s", tmp_name);
724		return err;
725	}
726
727	svol->elem.id = *ctl_id;
728	svol->max_val = resolution - 1;
729	svol->min_dB = min_dB;
730	svol->max_dB = max_dB;
731	if (svol->max_val == 1 || svol->max_dB == ZERO_DB)
732		svol->zero_dB_val = svol->max_val;
733	else if (svol->max_dB < 0)
734		svol->zero_dB_val = 0; /* there is no 0 dB setting */
735	else
736		svol->zero_dB_val = (min_dB / (min_dB - max_dB)) * svol->max_val;
737
738	snd_ctl_elem_info_alloca(&cinfo);
739	snd_ctl_elem_info_set_id(cinfo, ctl_id);
740	if ((err = snd_ctl_elem_info(svol->ctl, cinfo)) < 0) {
741		if (err != -ENOENT) {
742			SNDERR("Cannot get info for CTL %s", tmp_name);
743			return err;
744		}
745		err = add_user_ctl(svol, cinfo, cchannels);
746		if (err < 0) {
747			SNDERR("Cannot add a control");
748			return err;
749		}
750	} else {
751		if (! (cinfo->access & SNDRV_CTL_ELEM_ACCESS_USER)) {
752			/* hardware control exists */
753			return 1; /* notify */
754
755		} else if ((cinfo->type != SND_CTL_ELEM_TYPE_INTEGER &&
756			    cinfo->type != SND_CTL_ELEM_TYPE_BOOLEAN) ||
757			   cinfo->count != (unsigned int)cchannels ||
758			   cinfo->value.integer.min != 0 ||
759			   cinfo->value.integer.max != resolution - 1) {
760			if ((err = snd_ctl_elem_remove(svol->ctl, &cinfo->id)) < 0) {
761				SNDERR("Control %s mismatch", tmp_name);
762				return err;
763			}
764			snd_ctl_elem_info_set_id(cinfo, ctl_id); /* reset numid */
765			if ((err = add_user_ctl(svol, cinfo, cchannels)) < 0) {
766				SNDERR("Cannot add a control");
767				return err;
768			}
769		} else if (svol->max_val > 1) {
770			/* check TLV availability */
771			unsigned int tlv[4];
772			err = snd_ctl_elem_tlv_read(svol->ctl, &cinfo->id, tlv, sizeof(tlv));
773			if (err < 0)
774				add_tlv_info(svol, cinfo);
775		}
776	}
777
778	if (svol->max_val == 1)
779		return 0;
780
781	/* set up dB table */
782	if (min_dB == PRESET_MIN_DB && max_dB == ZERO_DB && resolution == PRESET_RESOLUTION)
783		svol->dB_value = (unsigned int*)preset_dB_value;
784	else {
785#ifndef HAVE_SOFT_FLOAT
786		svol->dB_value = calloc(resolution, sizeof(unsigned int));
787		if (! svol->dB_value) {
788			SNDERR("cannot allocate dB table");
789			return -ENOMEM;
790		}
791		svol->min_dB = min_dB;
792		svol->max_dB = max_dB;
793		for (i = 0; i <= svol->max_val; i++) {
794			double db = svol->min_dB + (i * (svol->max_dB - svol->min_dB)) / svol->max_val;
795			double v = (pow(10.0, db / 20.0) * (double)(1 << VOL_SCALE_SHIFT));
796			svol->dB_value[i] = (unsigned int)v;
797		}
798		if (svol->zero_dB_val)
799			svol->dB_value[svol->zero_dB_val] = 65535;
800#else
801		SNDERR("Cannot handle the given dB range and resolution");
802		return -EINVAL;
803#endif
804	}
805	return 0;
806}
807
808static const snd_pcm_ops_t snd_pcm_softvol_ops = {
809	.close = snd_pcm_softvol_close,
810	.info = snd_pcm_generic_info,
811	.hw_refine = snd_pcm_softvol_hw_refine,
812	.hw_params = snd_pcm_softvol_hw_params,
813	.hw_free = snd_pcm_generic_hw_free,
814	.sw_params = snd_pcm_generic_sw_params,
815	.channel_info = snd_pcm_generic_channel_info,
816	.dump = snd_pcm_softvol_dump,
817	.nonblock = snd_pcm_generic_nonblock,
818	.async = snd_pcm_generic_async,
819	.mmap = snd_pcm_generic_mmap,
820	.munmap = snd_pcm_generic_munmap,
821};
822
823/**
824 * \brief Creates a new SoftVolume PCM
825 * \param pcmp Returns created PCM handle
826 * \param name Name of PCM
827 * \param sformat Slave format
828 * \param ctl_card card index of the control
829 * \param ctl_id The control element
830 * \param cchannels PCM channels
831 * \param min_dB minimal dB value
832 * \param max_dB maximal dB value
833 * \param resolution resolution of control
834 * \param slave Slave PCM handle
835 * \param close_slave When set, the slave PCM handle is closed with copy PCM
836 * \retval zero on success otherwise a negative error code
837 * \warning Using of this function might be dangerous in the sense
838 *          of compatibility reasons. The prototype might be freely
839 *          changed in future.
840 */
841int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
842			 snd_pcm_format_t sformat,
843			 int ctl_card, snd_ctl_elem_id_t *ctl_id,
844			 int cchannels,
845			 double min_dB, double max_dB, int resolution,
846			 snd_pcm_t *slave, int close_slave)
847{
848	snd_pcm_t *pcm;
849	snd_pcm_softvol_t *svol;
850	int err;
851	assert(pcmp && slave);
852	if (sformat != SND_PCM_FORMAT_UNKNOWN &&
853	    sformat != SND_PCM_FORMAT_S16_LE &&
854	    sformat != SND_PCM_FORMAT_S16_BE &&
855	    sformat != SND_PCM_FORMAT_S24_3LE &&
856	    sformat != SND_PCM_FORMAT_S32_LE &&
857	    sformat != SND_PCM_FORMAT_S32_BE)
858		return -EINVAL;
859	svol = calloc(1, sizeof(*svol));
860	if (! svol)
861		return -ENOMEM;
862	err = softvol_load_control(slave, svol, ctl_card, ctl_id, cchannels,
863				   min_dB, max_dB, resolution);
864	if (err < 0) {
865		softvol_free(svol);
866		return err;
867	}
868	if (err > 0) { /* hardware control - no need for softvol! */
869		softvol_free(svol);
870		*pcmp = slave; /* just pass the slave */
871		if (!slave->name && name)
872			slave->name = strdup(name);
873		return 0;
874	}
875
876	/* do softvol */
877	snd_pcm_plugin_init(&svol->plug);
878	svol->sformat = sformat;
879	svol->cchannels = cchannels;
880	svol->plug.read = snd_pcm_softvol_read_areas;
881	svol->plug.write = snd_pcm_softvol_write_areas;
882	svol->plug.undo_read = snd_pcm_plugin_undo_read_generic;
883	svol->plug.undo_write = snd_pcm_plugin_undo_write_generic;
884	svol->plug.gen.slave = slave;
885	svol->plug.gen.close_slave = close_slave;
886
887	err = snd_pcm_new(&pcm, SND_PCM_TYPE_SOFTVOL, name, slave->stream, slave->mode);
888	if (err < 0) {
889		softvol_free(svol);
890		return err;
891	}
892	pcm->ops = &snd_pcm_softvol_ops;
893	pcm->fast_ops = &snd_pcm_plugin_fast_ops;
894	pcm->private_data = svol;
895	pcm->poll_fd = slave->poll_fd;
896	pcm->poll_events = slave->poll_events;
897	/*
898	 * Since the softvol converts on the place, and the format/channels
899	 * must be identical between source and destination, we don't need
900	 * an extra buffer.
901	 */
902	pcm->mmap_shadow = 1;
903	pcm->monotonic = slave->monotonic;
904	snd_pcm_set_hw_ptr(pcm, &svol->plug.hw_ptr, -1, 0);
905	snd_pcm_set_appl_ptr(pcm, &svol->plug.appl_ptr, -1, 0);
906	*pcmp = pcm;
907
908	return 0;
909}
910
911/* in pcm_misc.c */
912int snd_pcm_parse_control_id(snd_config_t *conf, snd_ctl_elem_id_t *ctl_id, int *cardp,
913			     int *cchannelsp, int *hwctlp);
914
915/*! \page pcm_plugins
916
917\section pcm_plugins_softvol Plugin: Soft Volume
918
919This plugin applies the software volume attenuation.
920The format, rate and channels must match for both of source and destination.
921
922When the control is stereo (count=2), the channels are assumed to be either
923mono, 2.0, 2.1, 4.0, 4.1, 5.1 or 7.1.
924
925If the control already exists and it's a system control (i.e. no
926user-defined control), the plugin simply passes its slave without
927any changes.
928
929\code
930pcm.name {
931        type softvol            # Soft Volume conversion PCM
932        slave STR               # Slave name
933        # or
934        slave {                 # Slave definition
935                pcm STR         # Slave PCM name
936                # or
937                pcm { }         # Slave PCM definition
938                [format STR]    # Slave format
939        }
940        control {
941	        name STR        # control element id string
942		[card STR]      # control card index
943		[iface STR]     # interface of the element
944		[index INT]     # index of the element
945		[device INT]    # device number of the element
946		[subdevice INT] # subdevice number of the element
947		[count INT]     # control channels 1 or 2 (default: 2)
948	}
949	[min_dB REAL]           # minimal dB value (default: -51.0)
950	[max_dB REAL]           # maximal dB value (default:   0.0)
951	[resolution INT]        # resolution (default: 256)
952				# resolution = 2 means a mute switch
953}
954\endcode
955
956\subsection pcm_plugins_softvol_funcref Function reference
957
958<UL>
959  <LI>snd_pcm_softvol_open()
960  <LI>_snd_pcm_softvol_open()
961</UL>
962
963*/
964
965/**
966 * \brief Creates a new Soft Volume PCM
967 * \param pcmp Returns created PCM handle
968 * \param name Name of PCM
969 * \param root Root configuration node
970 * \param conf Configuration node with Soft Volume PCM description
971 * \param stream Stream type
972 * \param mode Stream mode
973 * \retval zero on success otherwise a negative error code
974 * \warning Using of this function might be dangerous in the sense
975 *          of compatibility reasons. The prototype might be freely
976 *          changed in future.
977 */
978int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
979			  snd_config_t *root, snd_config_t *conf,
980			  snd_pcm_stream_t stream, int mode)
981{
982	snd_config_iterator_t i, next;
983	int err;
984	snd_pcm_t *spcm;
985	snd_config_t *slave = NULL, *sconf;
986	snd_config_t *control = NULL;
987	snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN;
988	snd_ctl_elem_id_t *ctl_id;
989	int resolution = PRESET_RESOLUTION;
990	double min_dB = PRESET_MIN_DB;
991	double max_dB = ZERO_DB;
992	int card = -1, cchannels = 2;
993
994	snd_config_for_each(i, next, conf) {
995		snd_config_t *n = snd_config_iterator_entry(i);
996		const char *id;
997		if (snd_config_get_id(n, &id) < 0)
998			continue;
999		if (snd_pcm_conf_generic_id(id))
1000			continue;
1001		if (strcmp(id, "slave") == 0) {
1002			slave = n;
1003			continue;
1004		}
1005		if (strcmp(id, "control") == 0) {
1006			control = n;
1007			continue;
1008		}
1009		if (strcmp(id, "resolution") == 0) {
1010			long v;
1011			err = snd_config_get_integer(n, &v);
1012			if (err < 0) {
1013				SNDERR("Invalid resolution value");
1014				return err;
1015			}
1016			resolution = v;
1017			continue;
1018		}
1019		if (strcmp(id, "min_dB") == 0) {
1020			err = snd_config_get_real(n, &min_dB);
1021			if (err < 0) {
1022				SNDERR("Invalid min_dB value");
1023				return err;
1024			}
1025			continue;
1026		}
1027		if (strcmp(id, "max_dB") == 0) {
1028			err = snd_config_get_real(n, &max_dB);
1029			if (err < 0) {
1030				SNDERR("Invalid max_dB value");
1031				return err;
1032			}
1033			continue;
1034		}
1035		SNDERR("Unknown field %s", id);
1036		return -EINVAL;
1037	}
1038	if (!slave) {
1039		SNDERR("slave is not defined");
1040		return -EINVAL;
1041	}
1042	if (!control) {
1043		SNDERR("control is not defined");
1044		return -EINVAL;
1045	}
1046	if (min_dB >= 0) {
1047		SNDERR("min_dB must be a negative value");
1048		return -EINVAL;
1049	}
1050	if (max_dB <= min_dB || max_dB > MAX_DB_UPPER_LIMIT) {
1051		SNDERR("max_dB must be larger than min_dB and less than %d dB",
1052		       MAX_DB_UPPER_LIMIT);
1053		return -EINVAL;
1054	}
1055	if (resolution <= 1 || resolution > 1024) {
1056		SNDERR("Invalid resolution value %d", resolution);
1057		return -EINVAL;
1058	}
1059	if (mode & SND_PCM_NO_SOFTVOL) {
1060		err = snd_pcm_slave_conf(root, slave, &sconf, 0);
1061		if (err < 0)
1062			return err;
1063		err = snd_pcm_open_named_slave(pcmp, name, root, sconf, stream,
1064					       mode, conf);
1065		snd_config_delete(sconf);
1066	} else {
1067		snd_ctl_elem_id_alloca(&ctl_id);
1068		err = snd_pcm_slave_conf(root, slave, &sconf, 1,
1069					 SND_PCM_HW_PARAM_FORMAT, 0, &sformat);
1070		if (err < 0)
1071			return err;
1072		if (sformat != SND_PCM_FORMAT_UNKNOWN &&
1073		    sformat != SND_PCM_FORMAT_S16_LE &&
1074		    sformat != SND_PCM_FORMAT_S16_BE &&
1075		    sformat != SND_PCM_FORMAT_S24_3LE &&
1076		    sformat != SND_PCM_FORMAT_S32_LE &&
1077		    sformat != SND_PCM_FORMAT_S32_BE) {
1078			SNDERR("only S16_LE, S16_BE, S24_3LE, S32_LE or S32_BE format "
1079			       "is supported");
1080			snd_config_delete(sconf);
1081			return -EINVAL;
1082		}
1083		err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
1084		snd_config_delete(sconf);
1085		if (err < 0)
1086			return err;
1087		if ((err = snd_pcm_parse_control_id(control, ctl_id, &card, &cchannels, NULL)) < 0) {
1088			snd_pcm_close(spcm);
1089			return err;
1090		}
1091		err = snd_pcm_softvol_open(pcmp, name, sformat, card, ctl_id, cchannels,
1092					   min_dB, max_dB, resolution, spcm, 1);
1093		if (err < 0)
1094			snd_pcm_close(spcm);
1095	}
1096	return err;
1097}
1098#ifndef DOC_HIDDEN
1099SND_DLSYM_BUILD_VERSION(_snd_pcm_softvol_open, SND_PCM_DLSYM_VERSION);
1100#endif
1101