1 /** 2 * \file pcm/pcm_softvol.c 3 * \ingroup PCM_Plugins 4 * \brief PCM Soft Volume Plugin Interface 5 * \author Takashi Iwai <tiwai (at) suse.de> 6 * \date 2004 7 */ 8 /* 9 * PCM - Soft Volume Plugin 10 * Copyright (c) 2004 by Takashi Iwai <tiwai (at) 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 */ 36 const char *_snd_module_pcm_softvol = ""; 37 #endif 38 39 #ifndef DOC_HIDDEN 40 41 typedef 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 64 static 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 */ 100 typedef union { 101 int i; 102 short s[2]; 103 } val_t; 104 static 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 int)v.s[0] * b; 111 y.s[0] = x.s[1]; 112 y.i += (int)v.s[1] * b; 113 #else 114 x.i = (unsigned int)v.s[1] * b; 115 y.s[1] = x.s[0]; 116 y.i += (int)v.s[0] * b; 117 #endif 118 return y.i; 119 } 120 121 static inline int MULTI_DIV_int(int a, unsigned int b, int swap) 122 { 123 unsigned int gain = (b >> VOL_SCALE_SHIFT); 124 int fraction; 125 a = swap ? (int)bswap_32(a) : a; 126 fraction = MULTI_DIV_32x16(a, b & VOL_SCALE_MASK); 127 if (gain) { 128 long long amp = (long long)a * gain + fraction; 129 if (amp > (int)0x7fffffff) 130 amp = (int)0x7fffffff; 131 else if (amp < (int)0x80000000) 132 amp = (int)0x80000000; 133 return swap ? (int)bswap_32((int)amp) : (int)amp; 134 } 135 return swap ? (int)bswap_32(fraction) : fraction; 136 } 137 138 static inline short MULTI_DIV_short(short a, unsigned int b, int swap) 139 { 140 unsigned int gain = b >> VOL_SCALE_SHIFT; 141 int fraction; 142 a = swap ? (short)bswap_16(a) : a; 143 fraction = (int)(a * (b & VOL_SCALE_MASK)) >> VOL_SCALE_SHIFT; 144 if (gain) { 145 int amp = a * gain + fraction; 146 if (abs(amp) > 0x7fff) 147 amp = (a<0) ? (short)0x8000 : (short)0x7fff; 148 return swap ? (short)bswap_16((short)amp) : (short)amp; 149 } 150 return swap ? (short)bswap_16((short)fraction) : (short)fraction; 151 } 152 153 #endif /* DOC_HIDDEN */ 154 155 /* 156 * apply volumue attenuation 157 * 158 * TODO: use SIMD operations 159 */ 160 161 #ifndef DOC_HIDDEN 162 #define CONVERT_AREA(TYPE, swap) do { \ 163 unsigned int ch, fr; \ 164 TYPE *src, *dst; \ 165 for (ch = 0; ch < channels; ch++) { \ 166 src_area = &src_areas[ch]; \ 167 dst_area = &dst_areas[ch]; \ 168 src = snd_pcm_channel_area_addr(src_area, src_offset); \ 169 dst = snd_pcm_channel_area_addr(dst_area, dst_offset); \ 170 src_step = snd_pcm_channel_area_step(src_area) / sizeof(TYPE); \ 171 dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(TYPE); \ 172 GET_VOL_SCALE; \ 173 fr = frames; \ 174 if (! vol_scale) { \ 175 while (fr--) { \ 176 *dst = 0; \ 177 dst += dst_step; \ 178 } \ 179 } else if (vol_scale == 0xffff) { \ 180 while (fr--) { \ 181 *dst = *src; \ 182 src += src_step; \ 183 dst += dst_step; \ 184 } \ 185 } else { \ 186 while (fr--) { \ 187 *dst = (TYPE) MULTI_DIV_##TYPE(*src, vol_scale, swap); \ 188 src += src_step; \ 189 dst += dst_step; \ 190 } \ 191 } \ 192 } \ 193 } while (0) 194 195 #define CONVERT_AREA_S24_3LE() do { \ 196 unsigned int ch, fr; \ 197 unsigned char *src, *dst; \ 198 int tmp; \ 199 for (ch = 0; ch < channels; ch++) { \ 200 src_area = &src_areas[ch]; \ 201 dst_area = &dst_areas[ch]; \ 202 src = snd_pcm_channel_area_addr(src_area, src_offset); \ 203 dst = snd_pcm_channel_area_addr(dst_area, dst_offset); \ 204 src_step = snd_pcm_channel_area_step(src_area); \ 205 dst_step = snd_pcm_channel_area_step(dst_area); \ 206 GET_VOL_SCALE; \ 207 fr = frames; \ 208 if (! vol_scale) { \ 209 while (fr--) { \ 210 dst[0] = dst[1] = dst[2] = 0; \ 211 dst += dst_step; \ 212 } \ 213 } else if (vol_scale == 0xffff) { \ 214 while (fr--) { \ 215 dst[0] = src[0]; \ 216 dst[1] = src[1]; \ 217 dst[2] = src[2]; \ 218 src += dst_step; \ 219 dst += src_step; \ 220 } \ 221 } else { \ 222 while (fr--) { \ 223 tmp = src[0] | \ 224 (src[1] << 8) | \ 225 (((signed char *) src)[2] << 16); \ 226 tmp = MULTI_DIV_int(tmp, vol_scale, 0); \ 227 dst[0] = tmp; \ 228 dst[1] = tmp >> 8; \ 229 dst[2] = tmp >> 16; \ 230 src += dst_step; \ 231 dst += src_step; \ 232 } \ 233 } \ 234 } \ 235 } while (0) 236 237 #define GET_VOL_SCALE \ 238 switch (ch) { \ 239 case 0: \ 240 case 2: \ 241 vol_scale = (channels == ch + 1) ? vol_c : vol[0]; \ 242 break; \ 243 case 4: \ 244 case 5: \ 245 vol_scale = vol_c; \ 246 break; \ 247 default: \ 248 vol_scale = vol[ch & 1]; \ 249 break; \ 250 } 251 252 #endif /* DOC_HIDDEN */ 253 254 /* 2-channel stereo control */ 255 static void softvol_convert_stereo_vol(snd_pcm_softvol_t *svol, 256 const snd_pcm_channel_area_t *dst_areas, 257 snd_pcm_uframes_t dst_offset, 258 const snd_pcm_channel_area_t *src_areas, 259 snd_pcm_uframes_t src_offset, 260 unsigned int channels, 261 snd_pcm_uframes_t frames) 262 { 263 const snd_pcm_channel_area_t *dst_area, *src_area; 264 unsigned int src_step, dst_step; 265 unsigned int vol_scale, vol[2], vol_c; 266 267 if (svol->cur_vol[0] == 0 && svol->cur_vol[1] == 0) { 268 snd_pcm_areas_silence(dst_areas, dst_offset, channels, frames, 269 svol->sformat); 270 return; 271 } else if (svol->zero_dB_val && svol->cur_vol[0] == svol->zero_dB_val && 272 svol->cur_vol[1] == svol->zero_dB_val) { 273 snd_pcm_areas_copy(dst_areas, dst_offset, src_areas, src_offset, 274 channels, frames, svol->sformat); 275 return; 276 } 277 278 if (svol->max_val == 1) { 279 vol[0] = svol->cur_vol[0] ? 0xffff : 0; 280 vol[1] = svol->cur_vol[1] ? 0xffff : 0; 281 vol_c = vol[0] | vol[1]; 282 } else { 283 vol[0] = svol->dB_value[svol->cur_vol[0]]; 284 vol[1] = svol->dB_value[svol->cur_vol[1]]; 285 vol_c = svol->dB_value[(svol->cur_vol[0] + svol->cur_vol[1]) / 2]; 286 } 287 switch (svol->sformat) { 288 case SND_PCM_FORMAT_S16_LE: 289 case SND_PCM_FORMAT_S16_BE: 290 /* 16bit samples */ 291 CONVERT_AREA(short, 292 !snd_pcm_format_cpu_endian(svol->sformat)); 293 break; 294 case SND_PCM_FORMAT_S32_LE: 295 case SND_PCM_FORMAT_S32_BE: 296 /* 32bit samples */ 297 CONVERT_AREA(int, 298 !snd_pcm_format_cpu_endian(svol->sformat)); 299 break; 300 case SND_PCM_FORMAT_S24_3LE: 301 CONVERT_AREA_S24_3LE(); 302 break; 303 default: 304 break; 305 } 306 } 307 308 #undef GET_VOL_SCALE 309 #define GET_VOL_SCALE 310 311 /* mono control */ 312 static void softvol_convert_mono_vol(snd_pcm_softvol_t *svol, 313 const snd_pcm_channel_area_t *dst_areas, 314 snd_pcm_uframes_t dst_offset, 315 const snd_pcm_channel_area_t *src_areas, 316 snd_pcm_uframes_t src_offset, 317 unsigned int channels, 318 snd_pcm_uframes_t frames) 319 { 320 const snd_pcm_channel_area_t *dst_area, *src_area; 321 unsigned int src_step, dst_step; 322 unsigned int vol_scale; 323 324 if (svol->cur_vol[0] == 0) { 325 snd_pcm_areas_silence(dst_areas, dst_offset, channels, frames, 326 svol->sformat); 327 return; 328 } else if (svol->zero_dB_val && svol->cur_vol[0] == svol->zero_dB_val) { 329 snd_pcm_areas_copy(dst_areas, dst_offset, src_areas, src_offset, 330 channels, frames, svol->sformat); 331 return; 332 } 333 334 if (svol->max_val == 1) 335 vol_scale = svol->cur_vol[0] ? 0xffff : 0; 336 else 337 vol_scale = svol->dB_value[svol->cur_vol[0]]; 338 switch (svol->sformat) { 339 case SND_PCM_FORMAT_S16_LE: 340 case SND_PCM_FORMAT_S16_BE: 341 /* 16bit samples */ 342 CONVERT_AREA(short, 343 !snd_pcm_format_cpu_endian(svol->sformat)); 344 break; 345 case SND_PCM_FORMAT_S32_LE: 346 case SND_PCM_FORMAT_S32_BE: 347 /* 32bit samples */ 348 CONVERT_AREA(int, 349 !snd_pcm_format_cpu_endian(svol->sformat)); 350 break; 351 case SND_PCM_FORMAT_S24_3LE: 352 CONVERT_AREA_S24_3LE(); 353 break; 354 default: 355 break; 356 } 357 } 358 359 /* 360 * get the current volume value from driver 361 * 362 * TODO: mmap support? 363 */ 364 static void get_current_volume(snd_pcm_softvol_t *svol) 365 { 366 unsigned int val; 367 unsigned int i; 368 369 if (snd_ctl_elem_read(svol->ctl, &svol->elem) < 0) 370 return; 371 for (i = 0; i < svol->cchannels; i++) { 372 val = svol->elem.value.integer.value[i]; 373 if (val > svol->max_val) 374 val = svol->max_val; 375 svol->cur_vol[i] = val; 376 } 377 } 378 379 static void softvol_free(snd_pcm_softvol_t *svol) 380 { 381 if (svol->plug.gen.close_slave) 382 snd_pcm_close(svol->plug.gen.slave); 383 if (svol->ctl) 384 snd_ctl_close(svol->ctl); 385 if (svol->dB_value && svol->dB_value != preset_dB_value) 386 free(svol->dB_value); 387 free(svol); 388 } 389 390 static int snd_pcm_softvol_close(snd_pcm_t *pcm) 391 { 392 snd_pcm_softvol_t *svol = pcm->private_data; 393 softvol_free(svol); 394 return 0; 395 } 396 397 static int snd_pcm_softvol_hw_refine_cprepare(snd_pcm_t *pcm, 398 snd_pcm_hw_params_t *params) 399 { 400 int err; 401 snd_pcm_softvol_t *svol = pcm->private_data; 402 snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; 403 snd_pcm_format_mask_t format_mask = { 404 { 405 (1ULL << SND_PCM_FORMAT_S16_LE) | 406 (1ULL << SND_PCM_FORMAT_S16_BE) | 407 (1ULL << SND_PCM_FORMAT_S32_LE) | 408 (1ULL << SND_PCM_FORMAT_S32_BE), 409 (1ULL << (SND_PCM_FORMAT_S24_3LE - 32)) 410 } 411 }; 412 if (svol->sformat != SND_PCM_FORMAT_UNKNOWN) { 413 snd_pcm_format_mask_none(&format_mask); 414 snd_pcm_format_mask_set(&format_mask, svol->sformat); 415 } 416 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 417 &access_mask); 418 if (err < 0) 419 return err; 420 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, 421 &format_mask); 422 if (err < 0) 423 return err; 424 err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); 425 if (err < 0) 426 return err; 427 err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0); 428 if (err < 0) 429 return err; 430 params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); 431 return 0; 432 } 433 434 static int snd_pcm_softvol_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) 435 { 436 snd_pcm_softvol_t *svol = pcm->private_data; 437 snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; 438 _snd_pcm_hw_params_any(sparams); 439 _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 440 &saccess_mask); 441 if (svol->sformat != SND_PCM_FORMAT_UNKNOWN) { 442 _snd_pcm_hw_params_set_format(sparams, svol->sformat); 443 _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); 444 } 445 return 0; 446 } 447 448 /* 449 * refine the access mask 450 */ 451 static int check_access_mask(snd_pcm_hw_params_t *src, 452 snd_pcm_hw_params_t *dst) 453 { 454 const snd_pcm_access_mask_t *mask; 455 snd_pcm_access_mask_t smask; 456 457 mask = snd_pcm_hw_param_get_mask(src, SND_PCM_HW_PARAM_ACCESS); 458 snd_mask_none(&smask); 459 if (snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_RW_INTERLEAVED) || 460 snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) { 461 snd_pcm_access_mask_set(&smask, 462 SND_PCM_ACCESS_RW_INTERLEAVED); 463 snd_pcm_access_mask_set(&smask, 464 SND_PCM_ACCESS_MMAP_INTERLEAVED); 465 } 466 if (snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) || 467 snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) { 468 snd_pcm_access_mask_set(&smask, 469 SND_PCM_ACCESS_RW_NONINTERLEAVED); 470 snd_pcm_access_mask_set(&smask, 471 SND_PCM_ACCESS_MMAP_NONINTERLEAVED); 472 } 473 if (snd_pcm_access_mask_test(mask, SND_PCM_ACCESS_MMAP_COMPLEX)) 474 snd_pcm_access_mask_set(&smask, 475 SND_PCM_ACCESS_MMAP_COMPLEX); 476 477 return _snd_pcm_hw_param_set_mask(dst, SND_PCM_HW_PARAM_ACCESS, &smask); 478 } 479 480 static int snd_pcm_softvol_hw_refine_schange(snd_pcm_t *pcm, 481 snd_pcm_hw_params_t *params, 482 snd_pcm_hw_params_t *sparams) 483 { 484 snd_pcm_softvol_t *svol = pcm->private_data; 485 int err; 486 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | 487 SND_PCM_HW_PARBIT_RATE | 488 SND_PCM_HW_PARBIT_PERIODS | 489 SND_PCM_HW_PARBIT_PERIOD_SIZE | 490 SND_PCM_HW_PARBIT_PERIOD_TIME | 491 SND_PCM_HW_PARBIT_BUFFER_SIZE | 492 SND_PCM_HW_PARBIT_BUFFER_TIME | 493 SND_PCM_HW_PARBIT_TICK_TIME); 494 if (svol->sformat == SND_PCM_FORMAT_UNKNOWN) 495 links |= (SND_PCM_HW_PARBIT_FORMAT | 496 SND_PCM_HW_PARBIT_SUBFORMAT | 497 SND_PCM_HW_PARBIT_SAMPLE_BITS); 498 err = _snd_pcm_hw_params_refine(sparams, links, params); 499 if (err < 0) 500 return err; 501 502 err = check_access_mask(params, sparams); 503 if (err < 0) 504 return err; 505 506 return 0; 507 } 508 509 static int snd_pcm_softvol_hw_refine_cchange(snd_pcm_t *pcm, 510 snd_pcm_hw_params_t *params, 511 snd_pcm_hw_params_t *sparams) 512 { 513 snd_pcm_softvol_t *svol = pcm->private_data; 514 int err; 515 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | 516 SND_PCM_HW_PARBIT_RATE | 517 SND_PCM_HW_PARBIT_PERIODS | 518 SND_PCM_HW_PARBIT_PERIOD_SIZE | 519 SND_PCM_HW_PARBIT_PERIOD_TIME | 520 SND_PCM_HW_PARBIT_BUFFER_SIZE | 521 SND_PCM_HW_PARBIT_BUFFER_TIME | 522 SND_PCM_HW_PARBIT_TICK_TIME); 523 if (svol->sformat == SND_PCM_FORMAT_UNKNOWN) 524 links |= (SND_PCM_HW_PARBIT_FORMAT | 525 SND_PCM_HW_PARBIT_SUBFORMAT | 526 SND_PCM_HW_PARBIT_SAMPLE_BITS); 527 err = _snd_pcm_hw_params_refine(params, links, sparams); 528 if (err < 0) 529 return err; 530 531 err = check_access_mask(sparams, params); 532 if (err < 0) 533 return err; 534 535 return 0; 536 } 537 538 static int snd_pcm_softvol_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 539 { 540 return snd_pcm_hw_refine_slave(pcm, params, 541 snd_pcm_softvol_hw_refine_cprepare, 542 snd_pcm_softvol_hw_refine_cchange, 543 snd_pcm_softvol_hw_refine_sprepare, 544 snd_pcm_softvol_hw_refine_schange, 545 snd_pcm_generic_hw_refine); 546 } 547 548 static int snd_pcm_softvol_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) 549 { 550 snd_pcm_softvol_t *svol = pcm->private_data; 551 snd_pcm_t *slave = svol->plug.gen.slave; 552 int err = snd_pcm_hw_params_slave(pcm, params, 553 snd_pcm_softvol_hw_refine_cchange, 554 snd_pcm_softvol_hw_refine_sprepare, 555 snd_pcm_softvol_hw_refine_schange, 556 snd_pcm_generic_hw_params); 557 if (err < 0) 558 return err; 559 if (slave->format != SND_PCM_FORMAT_S16_LE && 560 slave->format != SND_PCM_FORMAT_S16_BE && 561 slave->format != SND_PCM_FORMAT_S24_3LE && 562 slave->format != SND_PCM_FORMAT_S32_LE && 563 slave->format != SND_PCM_FORMAT_S32_BE) { 564 SNDERR("softvol supports only S16_LE, S16_BE, S24_3LE, S32_LE " 565 " or S32_BE"); 566 return -EINVAL; 567 } 568 svol->sformat = slave->format; 569 return 0; 570 } 571 572 static snd_pcm_uframes_t 573 snd_pcm_softvol_write_areas(snd_pcm_t *pcm, 574 const snd_pcm_channel_area_t *areas, 575 snd_pcm_uframes_t offset, 576 snd_pcm_uframes_t size, 577 const snd_pcm_channel_area_t *slave_areas, 578 snd_pcm_uframes_t slave_offset, 579 snd_pcm_uframes_t *slave_sizep) 580 { 581 snd_pcm_softvol_t *svol = pcm->private_data; 582 if (size > *slave_sizep) 583 size = *slave_sizep; 584 get_current_volume(svol); 585 if (svol->cchannels == 1) 586 softvol_convert_mono_vol(svol, slave_areas, slave_offset, 587 areas, offset, pcm->channels, size); 588 else 589 softvol_convert_stereo_vol(svol, slave_areas, slave_offset, 590 areas, offset, pcm->channels, size); 591 *slave_sizep = size; 592 return size; 593 } 594 595 static snd_pcm_uframes_t 596 snd_pcm_softvol_read_areas(snd_pcm_t *pcm, 597 const snd_pcm_channel_area_t *areas, 598 snd_pcm_uframes_t offset, 599 snd_pcm_uframes_t size, 600 const snd_pcm_channel_area_t *slave_areas, 601 snd_pcm_uframes_t slave_offset, 602 snd_pcm_uframes_t *slave_sizep) 603 { 604 snd_pcm_softvol_t *svol = pcm->private_data; 605 if (size > *slave_sizep) 606 size = *slave_sizep; 607 get_current_volume(svol); 608 if (svol->cchannels == 1) 609 softvol_convert_mono_vol(svol, areas, offset, slave_areas, 610 slave_offset, pcm->channels, size); 611 else 612 softvol_convert_stereo_vol(svol, areas, offset, slave_areas, 613 slave_offset, pcm->channels, size); 614 *slave_sizep = size; 615 return size; 616 } 617 618 static void snd_pcm_softvol_dump(snd_pcm_t *pcm, snd_output_t *out) 619 { 620 snd_pcm_softvol_t *svol = pcm->private_data; 621 snd_output_printf(out, "Soft volume PCM\n"); 622 snd_output_printf(out, "Control: %s\n", svol->elem.id.name); 623 if (svol->max_val == 1) 624 snd_output_printf(out, "boolean\n"); 625 else { 626 snd_output_printf(out, "min_dB: %g\n", svol->min_dB); 627 snd_output_printf(out, "max_dB: %g\n", svol->max_dB); 628 snd_output_printf(out, "resolution: %d\n", svol->max_val + 1); 629 } 630 if (pcm->setup) { 631 snd_output_printf(out, "Its setup is:\n"); 632 snd_pcm_dump_setup(pcm, out); 633 } 634 snd_output_printf(out, "Slave: "); 635 snd_pcm_dump(svol->plug.gen.slave, out); 636 } 637 638 static int add_tlv_info(snd_pcm_softvol_t *svol, snd_ctl_elem_info_t *cinfo) 639 { 640 unsigned int tlv[4]; 641 tlv[0] = SND_CTL_TLVT_DB_SCALE; 642 tlv[1] = 2 * sizeof(int); 643 tlv[2] = svol->min_dB * 100; 644 tlv[3] = (svol->max_dB - svol->min_dB) * 100 / svol->max_val; 645 return snd_ctl_elem_tlv_write(svol->ctl, &cinfo->id, tlv); 646 } 647 648 static int add_user_ctl(snd_pcm_softvol_t *svol, snd_ctl_elem_info_t *cinfo, int count) 649 { 650 int err; 651 int i; 652 unsigned int def_val; 653 654 if (svol->max_val == 1) 655 err = snd_ctl_elem_add_boolean(svol->ctl, &cinfo->id, count); 656 else 657 err = snd_ctl_elem_add_integer(svol->ctl, &cinfo->id, count, 658 0, svol->max_val, 0); 659 if (err < 0) 660 return err; 661 if (svol->max_val == 1) 662 def_val = 1; 663 else { 664 add_tlv_info(svol, cinfo); 665 /* set zero dB value as default, or max_val if 666 there is no 0 dB setting */ 667 def_val = svol->zero_dB_val ? svol->zero_dB_val : svol->max_val; 668 } 669 for (i = 0; i < count; i++) 670 svol->elem.value.integer.value[i] = def_val; 671 return snd_ctl_elem_write(svol->ctl, &svol->elem); 672 } 673 674 /* 675 * load and set up user-control 676 * returns 0 if the user-control is found or created, 677 * returns 1 if the control is a hw control, 678 * or a negative error code 679 */ 680 static int softvol_load_control(snd_pcm_t *pcm, snd_pcm_softvol_t *svol, 681 int ctl_card, snd_ctl_elem_id_t *ctl_id, 682 int cchannels, double min_dB, double max_dB, 683 int resolution) 684 { 685 char tmp_name[32]; 686 snd_pcm_info_t *info; 687 snd_ctl_elem_info_t *cinfo; 688 int err; 689 unsigned int i; 690 691 if (ctl_card < 0) { 692 snd_pcm_info_alloca(&info); 693 err = snd_pcm_info(pcm, info); 694 if (err < 0) 695 return err; 696 ctl_card = snd_pcm_info_get_card(info); 697 if (ctl_card < 0) { 698 SNDERR("No card defined for softvol control"); 699 return -EINVAL; 700 } 701 } 702 sprintf(tmp_name, "hw:%d", ctl_card); 703 err = snd_ctl_open(&svol->ctl, tmp_name, 0); 704 if (err < 0) { 705 SNDERR("Cannot open CTL %s", tmp_name); 706 return err; 707 } 708 709 svol->elem.id = *ctl_id; 710 svol->max_val = resolution - 1; 711 svol->min_dB = min_dB; 712 svol->max_dB = max_dB; 713 if (svol->max_val == 1 || svol->max_dB == ZERO_DB) 714 svol->zero_dB_val = svol->max_val; 715 else if (svol->max_dB < 0) 716 svol->zero_dB_val = 0; /* there is no 0 dB setting */ 717 else 718 svol->zero_dB_val = (min_dB / (min_dB - max_dB)) * svol->max_val; 719 720 snd_ctl_elem_info_alloca(&cinfo); 721 snd_ctl_elem_info_set_id(cinfo, ctl_id); 722 if ((err = snd_ctl_elem_info(svol->ctl, cinfo)) < 0) { 723 if (err != -ENOENT) { 724 SNDERR("Cannot get info for CTL %s", tmp_name); 725 return err; 726 } 727 err = add_user_ctl(svol, cinfo, cchannels); 728 if (err < 0) { 729 SNDERR("Cannot add a control"); 730 return err; 731 } 732 } else { 733 if (! (cinfo->access & SNDRV_CTL_ELEM_ACCESS_USER)) { 734 /* hardware control exists */ 735 return 1; /* notify */ 736 737 } else if ((cinfo->type != SND_CTL_ELEM_TYPE_INTEGER && 738 cinfo->type != SND_CTL_ELEM_TYPE_BOOLEAN) || 739 cinfo->count != (unsigned int)cchannels || 740 cinfo->value.integer.min != 0 || 741 cinfo->value.integer.max != resolution - 1) { 742 if ((err = snd_ctl_elem_remove(svol->ctl, &cinfo->id)) < 0) { 743 SNDERR("Control %s mismatch", tmp_name); 744 return err; 745 } 746 snd_ctl_elem_info_set_id(cinfo, ctl_id); /* reset numid */ 747 if ((err = add_user_ctl(svol, cinfo, cchannels)) < 0) { 748 SNDERR("Cannot add a control"); 749 return err; 750 } 751 } else if (svol->max_val > 1) { 752 /* check TLV availability */ 753 unsigned int tlv[4]; 754 err = snd_ctl_elem_tlv_read(svol->ctl, &cinfo->id, tlv, sizeof(tlv)); 755 if (err < 0) 756 add_tlv_info(svol, cinfo); 757 } 758 } 759 760 if (svol->max_val == 1) 761 return 0; 762 763 /* set up dB table */ 764 if (min_dB == PRESET_MIN_DB && max_dB == ZERO_DB && resolution == PRESET_RESOLUTION) 765 svol->dB_value = (unsigned int*)preset_dB_value; 766 else { 767 #ifndef HAVE_SOFT_FLOAT 768 svol->dB_value = calloc(resolution, sizeof(unsigned int)); 769 if (! svol->dB_value) { 770 SNDERR("cannot allocate dB table"); 771 return -ENOMEM; 772 } 773 svol->min_dB = min_dB; 774 svol->max_dB = max_dB; 775 for (i = 0; i <= svol->max_val; i++) { 776 double db = svol->min_dB + (i * (svol->max_dB - svol->min_dB)) / svol->max_val; 777 double v = (pow(10.0, db / 20.0) * (double)(1 << VOL_SCALE_SHIFT)); 778 svol->dB_value[i] = (unsigned int)v; 779 } 780 if (svol->zero_dB_val) 781 svol->dB_value[svol->zero_dB_val] = 65535; 782 #else 783 SNDERR("Cannot handle the given dB range and resolution"); 784 return -EINVAL; 785 #endif 786 } 787 return 0; 788 } 789 790 static const snd_pcm_ops_t snd_pcm_softvol_ops = { 791 .close = snd_pcm_softvol_close, 792 .info = snd_pcm_generic_info, 793 .hw_refine = snd_pcm_softvol_hw_refine, 794 .hw_params = snd_pcm_softvol_hw_params, 795 .hw_free = snd_pcm_generic_hw_free, 796 .sw_params = snd_pcm_generic_sw_params, 797 .channel_info = snd_pcm_generic_channel_info, 798 .dump = snd_pcm_softvol_dump, 799 .nonblock = snd_pcm_generic_nonblock, 800 .async = snd_pcm_generic_async, 801 .mmap = snd_pcm_generic_mmap, 802 .munmap = snd_pcm_generic_munmap, 803 }; 804 805 /** 806 * \brief Creates a new SoftVolume PCM 807 * \param pcmp Returns created PCM handle 808 * \param name Name of PCM 809 * \param sformat Slave format 810 * \param ctl_card card index of the control 811 * \param ctl_id The control element 812 * \param cchannels PCM channels 813 * \param min_dB minimal dB value 814 * \param max_dB maximal dB value 815 * \param resolution resolution of control 816 * \param slave Slave PCM handle 817 * \param close_slave When set, the slave PCM handle is closed with copy PCM 818 * \retval zero on success otherwise a negative error code 819 * \warning Using of this function might be dangerous in the sense 820 * of compatibility reasons. The prototype might be freely 821 * changed in future. 822 */ 823 int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, 824 snd_pcm_format_t sformat, 825 int ctl_card, snd_ctl_elem_id_t *ctl_id, 826 int cchannels, 827 double min_dB, double max_dB, int resolution, 828 snd_pcm_t *slave, int close_slave) 829 { 830 snd_pcm_t *pcm; 831 snd_pcm_softvol_t *svol; 832 int err; 833 assert(pcmp && slave); 834 if (sformat != SND_PCM_FORMAT_UNKNOWN && 835 sformat != SND_PCM_FORMAT_S16_LE && 836 sformat != SND_PCM_FORMAT_S16_BE && 837 sformat != SND_PCM_FORMAT_S24_3LE && 838 sformat != SND_PCM_FORMAT_S32_LE && 839 sformat != SND_PCM_FORMAT_S32_BE) 840 return -EINVAL; 841 svol = calloc(1, sizeof(*svol)); 842 if (! svol) 843 return -ENOMEM; 844 err = softvol_load_control(slave, svol, ctl_card, ctl_id, cchannels, 845 min_dB, max_dB, resolution); 846 if (err < 0) { 847 softvol_free(svol); 848 return err; 849 } 850 if (err > 0) { /* hardware control - no need for softvol! */ 851 softvol_free(svol); 852 *pcmp = slave; /* just pass the slave */ 853 if (!slave->name && name) 854 slave->name = strdup(name); 855 return 0; 856 } 857 858 /* do softvol */ 859 snd_pcm_plugin_init(&svol->plug); 860 svol->sformat = sformat; 861 svol->cchannels = cchannels; 862 svol->plug.read = snd_pcm_softvol_read_areas; 863 svol->plug.write = snd_pcm_softvol_write_areas; 864 svol->plug.undo_read = snd_pcm_plugin_undo_read_generic; 865 svol->plug.undo_write = snd_pcm_plugin_undo_write_generic; 866 svol->plug.gen.slave = slave; 867 svol->plug.gen.close_slave = close_slave; 868 869 err = snd_pcm_new(&pcm, SND_PCM_TYPE_SOFTVOL, name, slave->stream, slave->mode); 870 if (err < 0) { 871 softvol_free(svol); 872 return err; 873 } 874 pcm->ops = &snd_pcm_softvol_ops; 875 pcm->fast_ops = &snd_pcm_plugin_fast_ops; 876 pcm->private_data = svol; 877 pcm->poll_fd = slave->poll_fd; 878 pcm->poll_events = slave->poll_events; 879 /* 880 * Since the softvol converts on the place, and the format/channels 881 * must be identical between source and destination, we don't need 882 * an extra buffer. 883 */ 884 pcm->mmap_shadow = 1; 885 pcm->monotonic = slave->monotonic; 886 snd_pcm_set_hw_ptr(pcm, &svol->plug.hw_ptr, -1, 0); 887 snd_pcm_set_appl_ptr(pcm, &svol->plug.appl_ptr, -1, 0); 888 *pcmp = pcm; 889 890 return 0; 891 } 892 893 /* in pcm_misc.c */ 894 int snd_pcm_parse_control_id(snd_config_t *conf, snd_ctl_elem_id_t *ctl_id, int *cardp, 895 int *cchannelsp, int *hwctlp); 896 897 /*! \page pcm_plugins 898 899 \section pcm_plugins_softvol Plugin: Soft Volume 900 901 This plugin applies the software volume attenuation. 902 The format, rate and channels must match for both of source and destination. 903 904 When the control is stereo (count=2), the channels are assumed to be either 905 mono, 2.0, 2.1, 4.0, 4.1, 5.1 or 7.1. 906 907 If the control already exists and it's a system control (i.e. no 908 user-defined control), the plugin simply passes its slave without 909 any changes. 910 911 \code 912 pcm.name { 913 type softvol # Soft Volume conversion PCM 914 slave STR # Slave name 915 # or 916 slave { # Slave definition 917 pcm STR # Slave PCM name 918 # or 919 pcm { } # Slave PCM definition 920 [format STR] # Slave format 921 } 922 control { 923 name STR # control element id string 924 [card STR] # control card index 925 [iface STR] # interface of the element 926 [index INT] # index of the element 927 [device INT] # device number of the element 928 [subdevice INT] # subdevice number of the element 929 [count INT] # control channels 1 or 2 (default: 2) 930 } 931 [min_dB REAL] # minimal dB value (default: -51.0) 932 [max_dB REAL] # maximal dB value (default: 0.0) 933 [resolution INT] # resolution (default: 256) 934 # resolution = 2 means a mute switch 935 } 936 \endcode 937 938 \subsection pcm_plugins_softvol_funcref Function reference 939 940 <UL> 941 <LI>snd_pcm_softvol_open() 942 <LI>_snd_pcm_softvol_open() 943 </UL> 944 945 */ 946 947 /** 948 * \brief Creates a new Soft Volume PCM 949 * \param pcmp Returns created PCM handle 950 * \param name Name of PCM 951 * \param root Root configuration node 952 * \param conf Configuration node with Soft Volume PCM description 953 * \param stream Stream type 954 * \param mode Stream mode 955 * \retval zero on success otherwise a negative error code 956 * \warning Using of this function might be dangerous in the sense 957 * of compatibility reasons. The prototype might be freely 958 * changed in future. 959 */ 960 int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, 961 snd_config_t *root, snd_config_t *conf, 962 snd_pcm_stream_t stream, int mode) 963 { 964 snd_config_iterator_t i, next; 965 int err; 966 snd_pcm_t *spcm; 967 snd_config_t *slave = NULL, *sconf; 968 snd_config_t *control = NULL; 969 snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; 970 snd_ctl_elem_id_t *ctl_id; 971 int resolution = PRESET_RESOLUTION; 972 double min_dB = PRESET_MIN_DB; 973 double max_dB = ZERO_DB; 974 int card = -1, cchannels = 2; 975 976 snd_config_for_each(i, next, conf) { 977 snd_config_t *n = snd_config_iterator_entry(i); 978 const char *id; 979 if (snd_config_get_id(n, &id) < 0) 980 continue; 981 if (snd_pcm_conf_generic_id(id)) 982 continue; 983 if (strcmp(id, "slave") == 0) { 984 slave = n; 985 continue; 986 } 987 if (strcmp(id, "control") == 0) { 988 control = n; 989 continue; 990 } 991 if (strcmp(id, "resolution") == 0) { 992 long v; 993 err = snd_config_get_integer(n, &v); 994 if (err < 0) { 995 SNDERR("Invalid resolution value"); 996 return err; 997 } 998 resolution = v; 999 continue; 1000 } 1001 if (strcmp(id, "min_dB") == 0) { 1002 err = snd_config_get_real(n, &min_dB); 1003 if (err < 0) { 1004 SNDERR("Invalid min_dB value"); 1005 return err; 1006 } 1007 continue; 1008 } 1009 if (strcmp(id, "max_dB") == 0) { 1010 err = snd_config_get_real(n, &max_dB); 1011 if (err < 0) { 1012 SNDERR("Invalid max_dB value"); 1013 return err; 1014 } 1015 continue; 1016 } 1017 SNDERR("Unknown field %s", id); 1018 return -EINVAL; 1019 } 1020 if (!slave) { 1021 SNDERR("slave is not defined"); 1022 return -EINVAL; 1023 } 1024 if (!control) { 1025 SNDERR("control is not defined"); 1026 return -EINVAL; 1027 } 1028 if (min_dB >= 0) { 1029 SNDERR("min_dB must be a negative value"); 1030 return -EINVAL; 1031 } 1032 if (max_dB <= min_dB || max_dB > MAX_DB_UPPER_LIMIT) { 1033 SNDERR("max_dB must be larger than min_dB and less than %d dB", 1034 MAX_DB_UPPER_LIMIT); 1035 return -EINVAL; 1036 } 1037 if (resolution <= 1 || resolution > 1024) { 1038 SNDERR("Invalid resolution value %d", resolution); 1039 return -EINVAL; 1040 } 1041 if (mode & SND_PCM_NO_SOFTVOL) { 1042 err = snd_pcm_slave_conf(root, slave, &sconf, 0); 1043 if (err < 0) 1044 return err; 1045 err = snd_pcm_open_named_slave(pcmp, name, root, sconf, stream, 1046 mode, conf); 1047 snd_config_delete(sconf); 1048 } else { 1049 snd_ctl_elem_id_alloca(&ctl_id); 1050 err = snd_pcm_slave_conf(root, slave, &sconf, 1, 1051 SND_PCM_HW_PARAM_FORMAT, 0, &sformat); 1052 if (err < 0) 1053 return err; 1054 if (sformat != SND_PCM_FORMAT_UNKNOWN && 1055 sformat != SND_PCM_FORMAT_S16_LE && 1056 sformat != SND_PCM_FORMAT_S16_BE && 1057 sformat != SND_PCM_FORMAT_S24_3LE && 1058 sformat != SND_PCM_FORMAT_S32_LE && 1059 sformat != SND_PCM_FORMAT_S32_BE) { 1060 SNDERR("only S16_LE, S16_BE, S24_3LE, S32_LE or S32_BE format " 1061 "is supported"); 1062 snd_config_delete(sconf); 1063 return -EINVAL; 1064 } 1065 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); 1066 snd_config_delete(sconf); 1067 if (err < 0) 1068 return err; 1069 if ((err = snd_pcm_parse_control_id(control, ctl_id, &card, &cchannels, NULL)) < 0) { 1070 snd_pcm_close(spcm); 1071 return err; 1072 } 1073 err = snd_pcm_softvol_open(pcmp, name, sformat, card, ctl_id, cchannels, 1074 min_dB, max_dB, resolution, spcm, 1); 1075 if (err < 0) 1076 snd_pcm_close(spcm); 1077 } 1078 return err; 1079 } 1080 #ifndef DOC_HIDDEN 1081 SND_DLSYM_BUILD_VERSION(_snd_pcm_softvol_open, SND_PCM_DLSYM_VERSION); 1082 #endif 1083