int pa_cvolume_compatible_with_channel_map(const pa_cvolume *v, const pa_channel_map *cm) { pa_assert(v); pa_assert(cm); pa_return_val_if_fail(pa_cvolume_valid(v), 0); pa_return_val_if_fail(pa_channel_map_valid(cm), 0); return v->channels == cm->channels; }
pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { pa_return_val_if_fail(a != PA_VOLUME_INVALID, PA_VOLUME_INVALID); pa_return_val_if_fail(b != PA_VOLUME_INVALID, PA_VOLUME_INVALID); /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */ return (pa_volume_t) (((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM); }
pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); /* cbrt((a/PA_VOLUME_NORM)^3*(b/PA_VOLUME_NORM)^3)*PA_VOLUME_NORM = a*b/PA_VOLUME_NORM */ return (pa_volume_t) PA_CLAMP_VOLUME((((uint64_t) a * (uint64_t) b + (uint64_t) PA_VOLUME_NORM / 2ULL) / (uint64_t) PA_VOLUME_NORM)); }
int pa_channel_map_compatible(const pa_channel_map *map, const pa_sample_spec *ss) { pa_assert(map); pa_assert(ss); pa_return_val_if_fail(pa_channel_map_valid(map), 0); pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); return map->channels == ss->channels; }
pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) { pa_return_val_if_fail(PA_VOLUME_IS_VALID(a), PA_VOLUME_INVALID); pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), PA_VOLUME_INVALID); if (b <= PA_VOLUME_MUTED) return 0; return (pa_volume_t) (((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b); }
int pa_cvolume_compatible(const pa_cvolume *v, const pa_sample_spec *ss) { pa_assert(v); pa_assert(ss); pa_return_val_if_fail(pa_cvolume_valid(v), 0); pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); return v->channels == ss->channels; }
int pa_channel_map_has_position(const pa_channel_map *map, pa_channel_position_t p) { unsigned c; pa_return_val_if_fail(pa_channel_map_valid(map), 0); pa_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0); for (c = 0; c < map->channels; c++) if (map->map[c] == p) return 1; return 0; }
pa_cvolume* pa_cvolume_set_lfe_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) { pa_assert(map); pa_assert(v); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); pa_return_val_if_fail(new_balance >= -1.0f, NULL); pa_return_val_if_fail(new_balance <= 1.0f, NULL); if (!pa_channel_map_can_lfe_balance(map)) return v; return set_balance(v, map, new_balance, on_hfe, on_lfe); }
int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { unsigned c; pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), 0); pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0); for (c = 0; c < a->channels; c++) if (a->values[c] != v) return 0; return 1; }
pa_cvolume *pa_cvolume_remap(pa_cvolume *v, const pa_channel_map *from, const pa_channel_map *to) { int a, b; pa_cvolume result; pa_assert(v); pa_assert(from); pa_assert(to); pa_return_val_if_fail(pa_channel_map_valid(to), NULL); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL); if (pa_channel_map_equal(from, to)) return v; result.channels = to->channels; for (b = 0; b < to->channels; b++) { pa_volume_t k = 0; int n = 0; for (a = 0; a < from->channels; a++) if (from->map[a] == to->map[b]) { k += v->values[a]; n ++; } if (n <= 0) { for (a = 0; a < from->channels; a++) if ((on_left(from->map[a]) && on_left(to->map[b])) || (on_right(from->map[a]) && on_right(to->map[b])) || (on_center(from->map[a]) && on_center(to->map[b])) || (on_lfe(from->map[a]) && on_lfe(to->map[b]))) { k += v->values[a]; n ++; } } if (n <= 0) k = pa_cvolume_avg(v); else k /= n; result.values[b] = k; } *v = result; return v; }
pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) { uint64_t sum = 0; unsigned c, n; pa_assert(a); if (!cm) return pa_cvolume_avg(a); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(a, cm), PA_VOLUME_MUTED); for (c = n = 0; c < a->channels; c++) { if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask)) continue; sum += a->values[c]; n ++; } if (n > 0) sum /= n; return (pa_volume_t) sum; }
pa_cvolume *pa_sw_cvolume_divide_scalar(pa_cvolume *dest, const pa_cvolume *a, pa_volume_t b) { unsigned i; pa_assert(dest); pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(b), NULL); for (i = 0; i < a->channels; i++) dest->values[i] = pa_sw_volume_divide(a->values[i], b); dest->channels = (uint8_t) i; return dest; }
float pa_cvolume_get_balance(const pa_cvolume *v, const pa_channel_map *map) { pa_volume_t left, right; pa_assert(v); pa_assert(map); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f); if (!pa_channel_map_can_balance(map)) return 0.0f; get_avg_lr(map, v, &left, &right); if (left == right) return 0.0f; /* 1.0, 0.0 => -1.0 0.0, 1.0 => 1.0 0.0, 0.0 => 0.0 0.5, 0.5 => 0.0 1.0, 0.5 => -0.5 1.0, 0.25 => -0.75 0.75, 0.25 => -0.66 0.5, 0.25 => -0.5 */ if (left > right) return -1.0f + ((float) right / (float) left); else return 1.0f - ((float) left / (float) right); }
pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { pa_volume_t m; pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(dec), NULL); m = pa_cvolume_max(v); if (m <= PA_VOLUME_MUTED + dec) m = PA_VOLUME_MUTED; else m -= dec; return pa_cvolume_scale(v, m); }
pa_cvolume* pa_cvolume_merge(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { unsigned i; pa_assert(dest); pa_assert(a); pa_assert(b); pa_return_val_if_fail(pa_cvolume_valid(a), NULL); pa_return_val_if_fail(pa_cvolume_valid(b), NULL); for (i = 0; i < a->channels && i < b->channels; i++) dest->values[i] = PA_MAX(a->values[i], b->values[i]); dest->channels = (uint8_t) i; return dest; }
pa_cvolume* pa_cvolume_inc_clamp(pa_cvolume *v, pa_volume_t inc, pa_volume_t limit) { pa_volume_t m; pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(inc), NULL); m = pa_cvolume_max(v); if (m >= limit - inc) m = limit; else m += inc; return pa_cvolume_scale(v, m); }
double pa_sw_volume_to_dB(pa_volume_t v) { pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), PA_DECIBEL_MININFTY); if (v <= PA_VOLUME_MUTED) return PA_DECIBEL_MININFTY; return linear_to_dB(pa_sw_volume_to_linear(v)); }
/* For compressed streams */ pa_bool_t pa_format_info_to_sample_spec_fake(pa_format_info *f, pa_sample_spec *ss) { int rate; pa_assert(f); pa_assert(ss); pa_return_val_if_fail(f->encoding != PA_ENCODING_PCM, FALSE); ss->format = PA_SAMPLE_S16LE; ss->channels = 2; pa_return_val_if_fail(pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate), FALSE); ss->rate = (uint32_t) rate; if (f->encoding == PA_ENCODING_EAC3_IEC61937) ss->rate *= 4; return TRUE; }
int pa_channel_map_superset(const pa_channel_map *a, const pa_channel_map *b) { pa_channel_position_mask_t am, bm; pa_assert(a); pa_assert(b); pa_return_val_if_fail(pa_channel_map_valid(a), 0); if (PA_UNLIKELY(a == b)) return 1; pa_return_val_if_fail(pa_channel_map_valid(b), 0); am = pa_channel_map_mask(a); bm = pa_channel_map_mask(b); return (bm & am) == bm; }
pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) { unsigned c; pa_volume_t t = 0; pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); t = pa_cvolume_max(v); if (t <= PA_VOLUME_MUTED) return pa_cvolume_set(v, v->channels, max); for (c = 0; c < v->channels; c++) v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); return v; }
const char* pa_channel_map_to_pretty_name(const pa_channel_map *map) { pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)]; unsigned c; pa_assert(map); pa_return_val_if_fail(pa_channel_map_valid(map), NULL); memset(in_map, 0, sizeof(in_map)); for (c = 0; c < map->channels; c++) pa_bitset_set(in_map, map->map[c], TRUE); pa_init_i18n(); if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_MONO, -1)) return _("Mono"); if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1)) return _("Stereo"); if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1)) return _("Surround 4.0"); if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE, -1)) return _("Surround 4.1"); if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_FRONT_CENTER, -1)) return _("Surround 5.0"); if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1)) return _("Surround 5.1"); if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1)) return _("Surround 7.1"); return NULL; }
pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) { pa_volume_t front, nfront, rear, nrear, m; unsigned c; pa_assert(map); pa_assert(v); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); pa_return_val_if_fail(new_fade >= -1.0f, NULL); pa_return_val_if_fail(new_fade <= 1.0f, NULL); if (!pa_channel_map_can_fade(map)) return v; get_avg_fr(map, v, &front, &rear); m = PA_MAX(front, rear); if (new_fade <= 0) { nfront = (new_fade + 1.0f) * m; nrear = m; } else { nrear = (1.0f - new_fade) * m; nfront = m; } for (c = 0; c < map->channels; c++) { if (on_front(map->map[c])) { if (front == 0) v->values[c] = nfront; else v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nfront) / (uint64_t) front); } else if (on_rear(map->map[c])) { if (rear == 0) v->values[c] = nrear; else v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nrear) / (uint64_t) rear); } } return v; }
pa_cvolume* pa_cvolume_set_balance(pa_cvolume *v, const pa_channel_map *map, float new_balance) { pa_volume_t left, nleft, right, nright, m; unsigned c; pa_assert(map); pa_assert(v); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), NULL); pa_return_val_if_fail(new_balance >= -1.0f, NULL); pa_return_val_if_fail(new_balance <= 1.0f, NULL); if (!pa_channel_map_can_balance(map)) return v; get_avg_lr(map, v, &left, &right); m = PA_MAX(left, right); if (new_balance <= 0) { nright = (new_balance + 1.0f) * m; nleft = m; } else { nleft = (1.0f - new_balance) * m; nright = m; } for (c = 0; c < map->channels; c++) { if (on_left(map->map[c])) { if (left == 0) v->values[c] = nleft; else v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nleft) / (uint64_t) left); } else if (on_right(map->map[c])) { if (right == 0) v->values[c] = nright; else v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right); } } return v; }
pa_channel_position_mask_t pa_channel_map_mask(const pa_channel_map *map) { unsigned c; pa_channel_position_mask_t r = 0; pa_return_val_if_fail(pa_channel_map_valid(map), 0); for (c = 0; c < map->channels; c++) r |= PA_CHANNEL_POSITION_MASK(map->map[c]); return r; }
pa_volume_t pa_cvolume_get_position( pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) { unsigned c; pa_volume_t v = PA_VOLUME_MUTED; pa_assert(cv); pa_assert(map); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED); pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED); for (c = 0; c < map->channels; c++) if (map->map[c] == t) if (cv->values[c] > v) v = cv->values[c]; return v; }
int pa_channel_map_can_fade(const pa_channel_map *map) { pa_channel_position_mask_t m; pa_assert(map); pa_return_val_if_fail(pa_channel_map_valid(map), 0); m = pa_channel_map_mask(map); return (PA_CHANNEL_POSITION_MASK_FRONT & m) && (PA_CHANNEL_POSITION_MASK_REAR & m); }
const char* pa_channel_map_to_name(const pa_channel_map *map) { pa_bitset_t in_map[PA_BITSET_ELEMENTS(PA_CHANNEL_POSITION_MAX)]; unsigned c; pa_assert(map); pa_return_val_if_fail(pa_channel_map_valid(map), NULL); memset(in_map, 0, sizeof(in_map)); for (c = 0; c < map->channels; c++) pa_bitset_set(in_map, map->map[c], TRUE); if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_MONO, -1)) return "mono"; if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, -1)) return "stereo"; if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, -1)) return "surround-40"; if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE, -1)) return "surround-41"; if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_FRONT_CENTER, -1)) return "surround-50"; if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, -1)) return "surround-51"; if (pa_bitset_equals(in_map, PA_CHANNEL_POSITION_MAX, PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT, -1)) return "surround-71"; return NULL; }
pa_bool_t pa_format_info_get_prop_int(pa_format_info *f, const char *key, int *v) { const char *str; json_object *o; pa_assert(f); pa_assert(key); pa_assert(v); pa_return_val_if_fail(str = pa_proplist_gets(f->plist, key), FALSE); o = json_tokener_parse(str); pa_return_val_if_fail(!is_error(o), FALSE); if (json_object_get_type(o) != json_type_int) { json_object_put(o); return FALSE; } *v = json_object_get_int(o); json_object_put(o); return TRUE; }
int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { int i; pa_assert(a); pa_assert(b); pa_return_val_if_fail(pa_cvolume_valid(a), 0); if (PA_UNLIKELY(a == b)) return 1; pa_return_val_if_fail(pa_cvolume_valid(b), 0); if (a->channels != b->channels) return 0; for (i = 0; i < a->channels; i++) if (a->values[i] != b->values[i]) return 0; return 1; }
pa_volume_t pa_cvolume_min(const pa_cvolume *a) { pa_volume_t m = PA_VOLUME_MAX; unsigned c; pa_assert(a); pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED); for (c = 0; c < a->channels; c++) if (a->values[c] < m) m = a->values[c]; return m; }