1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2006 Lennart Poettering 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of the License, 9 or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <stdio.h> 25#include <string.h> 26#include <math.h> 27 28#include <pulsecore/core-util.h> 29#include <pulsecore/i18n.h> 30#include <pulsecore/macro.h> 31#include <pulsecore/sample-util.h> 32 33#include "volume.h" 34 35int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { 36 int i; 37 pa_assert(a); 38 pa_assert(b); 39 40 pa_return_val_if_fail(pa_cvolume_valid(a), 0); 41 42 if (PA_UNLIKELY(a == b)) 43 return 1; 44 45 pa_return_val_if_fail(pa_cvolume_valid(b), 0); 46 47 if (a->channels != b->channels) 48 return 0; 49 50 for (i = 0; i < a->channels; i++) 51 if (a->values[i] != b->values[i]) 52 return 0; 53 54 return 1; 55} 56 57pa_cvolume* pa_cvolume_init(pa_cvolume *a) { 58 unsigned c; 59 60 pa_assert(a); 61 62 a->channels = 0; 63 64 for (c = 0; c < PA_CHANNELS_MAX; c++) 65 a->values[c] = PA_VOLUME_INVALID; 66 67 return a; 68} 69 70pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { 71 int i; 72 73 pa_assert(a); 74 pa_assert(pa_channels_valid(channels)); 75 76 a->channels = (uint8_t) channels; 77 78 for (i = 0; i < a->channels; i++) 79 /* Clamp in case there is stale data that exceeds the current 80 * PA_VOLUME_MAX */ 81 a->values[i] = PA_CLAMP_VOLUME(v); 82 83 return a; 84} 85 86pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { 87 uint64_t sum = 0; 88 unsigned c; 89 90 pa_assert(a); 91 pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); 92 93 for (c = 0; c < a->channels; c++) 94 sum += a->values[c]; 95 96 sum /= a->channels; 97 98 return (pa_volume_t) sum; 99} 100 101pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { 102 uint64_t sum = 0; 103 unsigned c, n; 104 105 pa_assert(a); 106 107 if (!cm) 108 return pa_cvolume_avg(a); 109 110 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); 111 112 for (c = n = 0; c < a->channels; c++) { 113 114 if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) 115 continue; 116 117 sum += a->values[c]; 118 n ++; 119 } 120 121 if (n > 0) 122 sum /= n; 123 124 return (pa_volume_t) sum; 125} 126 127pa_volume_t pa_cvolume_max(const pa_cvolume *a) { 128 pa_volume_t m = PA_VOLUME_MUTED; 129 unsigned c; 130 131 pa_assert(a); 132 pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); 133 134 for (c = 0; c < a->channels; c++) 135 if (a->values[c] > m) 136 m = a->values[c]; 137 138 return m; 139} 140 141pa_volume_t pa_cvolume_min(const pa_cvolume *a) { 142 pa_volume_t m = PA_VOLUME_MAX; 143 unsigned c; 144 145 pa_assert(a); 146 pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); 147 148 for (c = 0; c < a->channels; c++) 149 if (a->values[c] < m) 150 m = a->values[c]; 151 152 return m; 153} 154 155pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { 156 pa_volume_t m = PA_VOLUME_MUTED; 157 unsigned c; 158 159 pa_assert(a); 160 161 if (!cm) 162 return pa_cvolume_max(a); 163 164 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); 165 166 for (c = 0; c < a->channels; c++) { 167 168 if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) 169 continue; 170 171 if (a->values[c] > m) 172 m = a->values[c]; 173 } 174 175 return m; 176} 177 178pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { 179 pa_volume_t m = PA_VOLUME_MAX; 180 unsigned c; 181 182 pa_assert(a); 183 184 if (!cm) 185 return pa_cvolume_min(a); 186 187 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); 188 189 for (c = 0; c < a->channels; c++) { 190 191 if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) 192 continue; 193 194 if (a->values[c] < m) 195 m = a->values[c]; 196 } 197 198 return m; 199} 200 201pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { 202 uint64_t result; 203 204 pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); 205 pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); 206 207 /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */ 208 209 result = ((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM; 210 211 if (result > (uint64_t)PA_VOLUME_MAX) 212 pa_log_warn("pa_sw_volume_multiply: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings."); 213 214 return (pa_volume_t) PA_CLAMP_VOLUME(result); 215} 216 217pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) { 218 uint64_t result; 219 220 pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); 221 pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); 222 223 if (b <= PA_VOLUME_MUTED) 224 return 0; 225 226 result = ((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b; 227 228 if (result > (uint64_t)PA_VOLUME_MAX) 229 pa_log_warn("pa_sw_volume_divide: Volume exceeds maximum allowed value and will be clipped. Please check your volume settings."); 230 231 return (pa_volume_t) PA_CLAMP_VOLUME(result); 232} 233 234/* Amplitude, not power */ 235static double linear_to_dB(double v) { 236 return 20.0 * log10(v); 237} 238 239static double dB_to_linear(double v) { 240 return pow(10.0, v / 20.0); 241} 242 243pa_volume_t pa_sw_volume_from_dB(double dB) { 244#ifdef __MUSL__ 245 if (dB == -INFINITY || dB <= PA_DECIBEL_MININFTY) 246 return PA_VOLUME_MUTED; 247#else 248 if (isinf(dB) < 0 || dB <= PA_DECIBEL_MININFTY) 249 return PA_VOLUME_MUTED; 250#endif // __MUSL__ 251 252 return pa_sw_volume_from_linear(dB_to_linear(dB)); 253} 254 255double pa_sw_volume_to_dB(pa_volume_t v) { 256 257 pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), PA_DECIBEL_MININFTY); 258 259 if (v <= PA_VOLUME_MUTED) 260 return PA_DECIBEL_MININFTY; 261 262 return linear_to_dB(pa_sw_volume_to_linear(v)); 263} 264 265pa_volume_t pa_sw_volume_from_linear(double v) { 266 267 if (v <= 0.0) 268 return PA_VOLUME_MUTED; 269 270 /* 271 * We use a cubic mapping here, as suggested and discussed here: 272 * 273 * http://www.robotplanet.dk/audio/audio_gui_design/ 274 * http://lists.linuxaudio.org/pipermail/linux-audio-dev/2009-May/thread.html#23151 275 * 276 * We make sure that the conversion to linear and back yields the 277 * same volume value! That's why we need the lround() below! 278 */ 279 280 return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM)); 281} 282 283double pa_sw_volume_to_linear(pa_volume_t v) { 284 double f; 285 286 pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0.0); 287 288 if (v <= PA_VOLUME_MUTED) 289 return 0.0; 290 291 if (v == PA_VOLUME_NORM) 292 return 1.0; 293 294 f = ((double) v / PA_VOLUME_NORM); 295 296 return f*f*f; 297} 298 299char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { 300 unsigned channel; 301 bool first = true; 302 char *e; 303 304 pa_assert(s); 305 pa_assert(l > 0); 306 pa_assert(c); 307 308 pa_init_i18n(); 309 310 if (!pa_cvolume_valid(c)) { 311 pa_snprintf(s, l, _("(invalid)")); 312 return s; 313 } 314 315 *(e = s) = 0; 316 317 for (channel = 0; channel < c->channels && l > 1; channel++) { 318 l -= pa_snprintf(e, l, "%s%u: %3u%%", 319 first ? "" : " ", 320 channel, 321 (unsigned)(((uint64_t)c->values[channel] * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM)); 322 323 e = strchr(e, 0); 324 first = false; 325 } 326 327 return s; 328} 329 330char *pa_volume_snprint(char *s, size_t l, pa_volume_t v) { 331 pa_assert(s); 332 pa_assert(l > 0); 333 334 pa_init_i18n(); 335 336 if (!PA_VOLUME_IS_VALID(v)) { 337 pa_snprintf(s, l, _("(invalid)")); 338 return s; 339 } 340 341 pa_snprintf(s, l, "%3u%%", (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM)); 342 return s; 343} 344 345char *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) { 346 unsigned channel; 347 bool first = true; 348 char *e; 349 350 pa_assert(s); 351 pa_assert(l > 0); 352 pa_assert(c); 353 354 pa_init_i18n(); 355 356 if (!pa_cvolume_valid(c)) { 357 pa_snprintf(s, l, _("(invalid)")); 358 return s; 359 } 360 361 *(e = s) = 0; 362 363 for (channel = 0; channel < c->channels && l > 1; channel++) { 364 double f = pa_sw_volume_to_dB(c->values[channel]); 365 366#ifdef __MUSL__ 367 l -= pa_snprintf(e, l, "%s%u: %0.2f dB", 368 first ? "" : " ", 369 channel, 370 f == -INFINITY || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); 371#else 372 l -= pa_snprintf(e, l, "%s%u: %0.2f dB", 373 first ? "" : " ", 374 channel, 375 isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); 376#endif // __MUSL__ 377 378 e = strchr(e, 0); 379 first = false; 380 } 381 382 return s; 383} 384 385char *pa_cvolume_snprint_verbose(char *s, size_t l, const pa_cvolume *c, const pa_channel_map *map, int print_dB) { 386 char *current = s; 387 bool first = true; 388 389 pa_assert(s); 390 pa_assert(l > 0); 391 pa_assert(c); 392 393 pa_init_i18n(); 394 395 if (!pa_cvolume_valid(c)) { 396 pa_snprintf(s, l, _("(invalid)")); 397 return s; 398 } 399 400 pa_assert(!map || (map->channels == c->channels)); 401 pa_assert(!map || pa_channel_map_valid(map)); 402 403 current[0] = 0; 404 405 for (unsigned channel = 0; channel < c->channels && l > 1; channel++) { 406 char channel_position[32]; 407 size_t bytes_printed; 408 char buf[PA_VOLUME_SNPRINT_VERBOSE_MAX]; 409 410 if (map) 411 pa_snprintf(channel_position, sizeof(channel_position), "%s", pa_channel_position_to_string(map->map[channel])); 412 else 413 pa_snprintf(channel_position, sizeof(channel_position), "%u", channel); 414 415 bytes_printed = pa_snprintf(current, l, "%s%s: %s", 416 first ? "" : ", ", 417 channel_position, 418 pa_volume_snprint_verbose(buf, sizeof(buf), c->values[channel], print_dB)); 419 l -= bytes_printed; 420 current += bytes_printed; 421 first = false; 422 } 423 424 return s; 425} 426 427char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v) { 428 double f; 429 430 pa_assert(s); 431 pa_assert(l > 0); 432 433 pa_init_i18n(); 434 435 if (!PA_VOLUME_IS_VALID(v)) { 436 pa_snprintf(s, l, _("(invalid)")); 437 return s; 438 } 439 440 f = pa_sw_volume_to_dB(v); 441#ifdef __MUSL__ 442 pa_snprintf(s, l, "%0.2f dB", f == -INFINITY || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); 443#else 444 pa_snprintf(s, l, "%0.2f dB", isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f); 445#endif // __MUSL__ 446 447 return s; 448} 449 450char *pa_volume_snprint_verbose(char *s, size_t l, pa_volume_t v, int print_dB) { 451 char dB[PA_SW_VOLUME_SNPRINT_DB_MAX]; 452 453 pa_assert(s); 454 pa_assert(l > 0); 455 456 pa_init_i18n(); 457 458 if (!PA_VOLUME_IS_VALID(v)) { 459 pa_snprintf(s, l, _("(invalid)")); 460 return s; 461 } 462 463 pa_snprintf(s, l, "%" PRIu32 " / %3u%%%s%s", 464 v, 465 (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM), 466 print_dB ? " / " : "", 467 print_dB ? pa_sw_volume_snprint_dB(dB, sizeof(dB), v) : ""); 468 469 return s; 470} 471 472int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { 473 unsigned c; 474 pa_assert(a); 475 476 pa_return_val_if_fail(pa_cvolume_valid(a), 0); 477 pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0); 478 479 for (c = 0; c < a->channels; c++) 480 if (a->values[c] != v) 481 return 0; 482 483 return 1; 484} 485 486pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { 487 unsigned i; 488 489 pa_assert(dest); 490 pa_assert(a); 491 pa_assert(b); 492 493 pa_return_val_if_fail(pa_cvolume_valid(a), NULL); 494 pa_return_val_if_fail(pa_cvolume_valid(b), NULL); 495 496 dest->channels = PA_MIN(a->channels, b->channels); 497 498 for (i = 0; i < dest->channels; i++) 499 dest->values[i] = pa_sw_volume_multiply(a->values[i], b->values[i]); 500 501 return dest; 502} 503 504pa_cvolume *pa_sw_cvolume_multiply_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { 505 unsigned i; 506 507 pa_assert(dest); 508 pa_assert(a); 509 510 pa_return_val_if_fail(pa_cvolume_valid(a), NULL); 511 pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL); 512 513 for (i = 0; i < a->channels; i++) 514 dest->values[i] = pa_sw_volume_multiply(a->values[i], b); 515 516 dest->channels = (uint8_t) i; 517 518 return dest; 519} 520 521pa_cvolume *pa_sw_cvolume_divide(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { 522 unsigned i; 523 524 pa_assert(dest); 525 pa_assert(a); 526 pa_assert(b); 527 528 pa_return_val_if_fail(pa_cvolume_valid(a), NULL); 529 pa_return_val_if_fail(pa_cvolume_valid(b), NULL); 530 531 dest->channels = PA_MIN(a->channels, b->channels); 532 533 for (i = 0; i < dest->channels; i++) 534 dest->values[i] = pa_sw_volume_divide(a->values[i], b->values[i]); 535 536 return dest; 537} 538 539pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { 540 unsigned i; 541 542 pa_assert(dest); 543 pa_assert(a); 544 545 pa_return_val_if_fail(pa_cvolume_valid(a), NULL); 546 pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL); 547 548 for (i = 0; i < a->channels; i++) 549 dest->values[i] = pa_sw_volume_divide(a->values[i], b); 550 551 dest->channels = (uint8_t) i; 552 553 return dest; 554} 555 556int pa_cvolume_valid(const pa_cvolume *v) { 557 unsigned c; 558 559 pa_assert(v); 560 561 if (!pa_channels_valid(v->channels)) 562 return 0; 563 564 for (c = 0; c < v->channels; c++) 565 if (!PA_VOLUME_IS_VALID(v->values[c])) 566 return 0; 567 568 return 1; 569} 570 571static bool on_left(pa_channel_position_t p) { 572 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT); 573} 574 575static bool on_right(pa_channel_position_t p) { 576 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT); 577} 578 579static bool on_center(pa_channel_position_t p) { 580 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER); 581} 582 583static bool on_hfe(pa_channel_position_t p) { 584 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_HFE); 585} 586 587static bool on_lfe(pa_channel_position_t p) { 588 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LFE); 589} 590 591static bool on_front(pa_channel_position_t p) { 592 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT); 593} 594 595static bool on_rear(pa_channel_position_t p) { 596 return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR); 597} 598 599pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) { 600 int a, b; 601 pa_cvolume result; 602 603 pa_assert(v); 604 pa_assert(from); 605 pa_assert(to); 606 607 pa_return_val_if_fail(pa_channel_map_valid(to), NULL); 608 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL); 609 610 if (pa_channel_map_equal(from, to)) 611 return v; 612 613 result.channels = to->channels; 614 615 for (b = 0; b < to->channels; b++) { 616 pa_volume_t k = 0; 617 int n = 0; 618 619 for (a = 0; a < from->channels; a++) 620 if (from->map[a] == to->map[b]) { 621 k += v->values[a]; 622 n ++; 623 } 624 625 if (n <= 0) { 626 for (a = 0; a < from->channels; a++) 627 if ((on_left(from->map[a]) && on_left(to->map[b])) || 628 (on_right(from->map[a]) && on_right(to->map[b])) || 629 (on_center(from->map[a]) && on_center(to->map[b])) || 630 (on_lfe(from->map[a]) && on_lfe(to->map[b]))) { 631 632 k += v->values[a]; 633 n ++; 634 } 635 } 636 637 if (n <= 0) 638 k = pa_cvolume_avg(v); 639 else 640 k /= n; 641 642 result.values[b] = k; 643 } 644 645 *v = result; 646 return v; 647} 648 649int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) { 650 651 pa_assert(v); 652 pa_assert(ss); 653 654 pa_return_val_if_fail(pa_cvolume_valid(v), 0); 655 pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); 656 657 return v->channels == ss->channels; 658} 659 660int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) { 661 pa_assert(v); 662 pa_assert(cm); 663 664 pa_return_val_if_fail(pa_cvolume_valid(v), 0); 665 pa_return_val_if_fail(pa_channel_map_valid(cm), 0); 666 667 return v->channels == cm->channels; 668} 669 670/* 671 * Returns the average volume of l and r, where l and r are two disjoint sets of channels 672 * (e g left and right, or front and rear). 673 */ 674static void get_avg(const pa_channel_map *map, const pa_cvolume *v, pa_volume_t *l, pa_volume_t *r, 675 bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) { 676 int c; 677 pa_volume_t left = 0, right = 0; 678 unsigned n_left = 0, n_right = 0; 679 680 pa_assert(v); 681 pa_assert(map); 682 pa_assert(map->channels == v->channels); 683 pa_assert(l); 684 pa_assert(r); 685 686 for (c = 0; c < map->channels; c++) { 687 if (on_l(map->map[c])) { 688 left += v->values[c]; 689 n_left++; 690 } else if (on_r(map->map[c])) { 691 right += v->values[c]; 692 n_right++; 693 } 694 } 695 696 if (n_left <= 0) 697 *l = PA_VOLUME_NORM; 698 else 699 *l = left / n_left; 700 701 if (n_right <= 0) 702 *r = PA_VOLUME_NORM; 703 else 704 *r = right / n_right; 705} 706 707float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) { 708 pa_volume_t left, right; 709 710 pa_assert(v); 711 pa_assert(map); 712 713 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); 714 715 if (!pa_channel_map_can_balance(map)) 716 return 0.0f; 717 718 get_avg(map, v, &left, &right, on_left, on_right); 719 720 if (left == right) 721 return 0.0f; 722 723 /* 1.0, 0.0 => -1.0 724 0.0, 1.0 => 1.0 725 0.0, 0.0 => 0.0 726 0.5, 0.5 => 0.0 727 1.0, 0.5 => -0.5 728 1.0, 0.25 => -0.75 729 0.75, 0.25 => -0.66 730 0.5, 0.25 => -0.5 */ 731 732 if (left > right) 733 return -1.0f + ((float) right / (float) left); 734 else 735 return 1.0f - ((float) left / (float) right); 736} 737 738static pa_cvolume* set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance, 739 bool (*on_l)(pa_channel_position_t), bool (*on_r)(pa_channel_position_t)) { 740 741 pa_volume_t left, nleft, right, nright, m; 742 unsigned c; 743 744 get_avg(map, v, &left, &right, on_l, on_r); 745 746 m = PA_MAX(left, right); 747 748 if (new_balance <= 0) { 749 nright = (new_balance + 1.0f) * m; 750 nleft = m; 751 } else { 752 nleft = (1.0f - new_balance) * m; 753 nright = m; 754 } 755 756 for (c = 0; c < map->channels; c++) { 757 if (on_l(map->map[c])) { 758 if (left == 0) 759 v->values[c] = nleft; 760 else 761 v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nleft) / (uint64_t) left); 762 } else if (on_r(map->map[c])) { 763 if (right == 0) 764 v->values[c] = nright; 765 else 766 v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right); 767 } 768 } 769 770 return v; 771} 772 773 774pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) { 775 pa_assert(map); 776 pa_assert(v); 777 778 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); 779 pa_return_val_if_fail(new_balance >= -1.0f, NULL); 780 pa_return_val_if_fail(new_balance <= 1.0f, NULL); 781 782 if (!pa_channel_map_can_balance(map)) 783 return v; 784 785 return set_balance(v, map, new_balance, on_left, on_right); 786} 787 788pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) { 789 unsigned c; 790 pa_volume_t t = 0; 791 792 pa_assert(v); 793 794 pa_return_val_if_fail(pa_cvolume_valid(v), NULL); 795 pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); 796 797 t = pa_cvolume_max(v); 798 799 if (t <= PA_VOLUME_MUTED) 800 return pa_cvolume_set(v, v->channels, max); 801 802 for (c = 0; c < v->channels; c++) 803 v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); 804 805 return v; 806} 807 808pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, const pa_channel_map *cm, pa_channel_position_mask_t mask) { 809 unsigned c; 810 pa_volume_t t = 0; 811 812 pa_assert(v); 813 814 pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); 815 816 if (!cm) 817 return pa_cvolume_scale(v, max); 818 819 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL); 820 821 t = pa_cvolume_max_mask(v, cm, mask); 822 823 if (t <= PA_VOLUME_MUTED) 824 return pa_cvolume_set(v, v->channels, max); 825 826 for (c = 0; c < v->channels; c++) 827 v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); 828 829 return v; 830} 831 832float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) { 833 pa_volume_t rear, front; 834 835 pa_assert(v); 836 pa_assert(map); 837 838 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); 839 840 if (!pa_channel_map_can_fade(map)) 841 return 0.0f; 842 843 get_avg(map, v, &rear, &front, on_rear, on_front); 844 845 if (front == rear) 846 return 0.0f; 847 848 if (rear > front) 849 return -1.0f + ((float) front / (float) rear); 850 else 851 return 1.0f - ((float) rear / (float) front); 852} 853 854pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) { 855 pa_assert(map); 856 pa_assert(v); 857 858 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); 859 pa_return_val_if_fail(new_fade >= -1.0f, NULL); 860 pa_return_val_if_fail(new_fade <= 1.0f, NULL); 861 862 if (!pa_channel_map_can_fade(map)) 863 return v; 864 865 return set_balance(v, map, new_fade, on_rear, on_front); 866} 867 868float pa_cvolume_get_lfe_balance(const pa_cvolume *v, const pa_channel_map *map) { 869 pa_volume_t hfe, lfe; 870 871 pa_assert(v); 872 pa_assert(map); 873 874 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); 875 876 if (!pa_channel_map_can_lfe_balance(map)) 877 return 0.0f; 878 879 get_avg(map, v, &hfe, &lfe, on_hfe, on_lfe); 880 881 if (hfe == lfe) 882 return 0.0f; 883 884 if (hfe > lfe) 885 return -1.0f + ((float) lfe / (float) hfe); 886 else 887 return 1.0f - ((float) hfe / (float) lfe); 888} 889 890pa_cvolume* pa_cvolume_set_lfe_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) { 891 pa_assert(map); 892 pa_assert(v); 893 894 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); 895 pa_return_val_if_fail(new_balance >= -1.0f, NULL); 896 pa_return_val_if_fail(new_balance <= 1.0f, NULL); 897 898 if (!pa_channel_map_can_lfe_balance(map)) 899 return v; 900 901 return set_balance(v, map, new_balance, on_hfe, on_lfe); 902} 903 904pa_cvolume* pa_cvolume_set_position( 905 pa_cvolume *cv, 906 const pa_channel_map *map, 907 pa_channel_position_t t, 908 pa_volume_t v) { 909 910 unsigned c; 911 bool good = false; 912 913 pa_assert(cv); 914 pa_assert(map); 915 916 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL); 917 pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL); 918 pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), NULL); 919 920 for (c = 0; c < map->channels; c++) 921 if (map->map[c] == t) { 922 cv->values[c] = v; 923 good = true; 924 } 925 926 return good ? cv : NULL; 927} 928 929pa_volume_t pa_cvolume_get_position( 930 const pa_cvolume *cv, 931 const pa_channel_map *map, 932 pa_channel_position_t t) { 933 934 unsigned c; 935 pa_volume_t v = PA_VOLUME_MUTED; 936 937 pa_assert(cv); 938 pa_assert(map); 939 940 pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED); 941 pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED); 942 943 for (c = 0; c < map->channels; c++) 944 if (map->map[c] == t) 945 if (cv->values[c] > v) 946 v = cv->values[c]; 947 948 return v; 949} 950 951pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { 952 unsigned i; 953 954 pa_assert(dest); 955 pa_assert(a); 956 pa_assert(b); 957 958 pa_return_val_if_fail(pa_cvolume_valid(a), NULL); 959 pa_return_val_if_fail(pa_cvolume_valid(b), NULL); 960 961 dest->channels = PA_MIN(a->channels, b->channels); 962 963 for (i = 0; i < dest->channels; i++) 964 dest->values[i] = PA_MAX(a->values[i], b->values[i]); 965 966 return dest; 967} 968 969pa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) { 970 pa_volume_t m; 971 972 pa_assert(v); 973 974 pa_return_val_if_fail(pa_cvolume_valid(v), NULL); 975 pa_return_val_if_fail(PA_VOLUME_IS_VALID(inc), NULL); 976 977 m = pa_cvolume_max(v); 978 979 if (m >= limit - inc) 980 m = limit; 981 else 982 m += inc; 983 984 return pa_cvolume_scale(v, m); 985} 986 987pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) { 988 return pa_cvolume_inc_clamp(v, inc, PA_VOLUME_MAX); 989} 990 991pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { 992 pa_volume_t m; 993 994 pa_assert(v); 995 996 pa_return_val_if_fail(pa_cvolume_valid(v), NULL); 997 pa_return_val_if_fail(PA_VOLUME_IS_VALID(dec), NULL); 998 999 m = pa_cvolume_max(v); 1000 1001 if (m <= PA_VOLUME_MUTED + dec) 1002 m = PA_VOLUME_MUTED; 1003 else 1004 m -= dec; 1005 1006 return pa_cvolume_scale(v, m); 1007} 1008