volume: implement pa_cvolume_{scale|max|avg}_mask()

This commit is contained in:
Lennart Poettering 2009-05-25 23:55:44 +02:00
parent 5f2d848d8e
commit 8b180b6368
3 changed files with 102 additions and 12 deletions

View file

@ -112,6 +112,7 @@ pa_context_suspend_source_by_name;
pa_context_unload_module;
pa_context_unref;
pa_cvolume_avg;
pa_cvolume_avg_mask;
pa_cvolume_channels_equal_to;
pa_cvolume_compatible;
pa_cvolume_compatible_with_channel_map;
@ -121,8 +122,10 @@ pa_cvolume_get_fade;
pa_cvolume_get_position;
pa_cvolume_init;
pa_cvolume_max;
pa_cvolume_max_mask;
pa_cvolume_remap;
pa_cvolume_scale;
pa_cvolume_scale_mask;
pa_cvolume_set;
pa_cvolume_set_balance;
pa_cvolume_set_fade;

View file

@ -80,29 +80,78 @@ pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) {
pa_volume_t pa_cvolume_avg(const pa_cvolume *a) {
uint64_t sum = 0;
int i;
unsigned c;
pa_assert(a);
pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
for (i = 0; i < a->channels; i++)
sum += a->values[i];
for (c = 0; c < a->channels; c++)
sum += a->values[c];
sum /= a->channels;
return (pa_volume_t) sum;
}
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_volume_t pa_cvolume_max(const pa_cvolume *a) {
pa_volume_t m = 0;
int i;
unsigned c;
pa_assert(a);
pa_return_val_if_fail(pa_cvolume_valid(a), PA_VOLUME_MUTED);
for (i = 0; i < a->channels; i++)
if (a->values[i] > m)
m = a->values[i];
for (c = 0; c < a->channels; c++)
if (a->values[c] > m)
m = a->values[c];
return m;
}
pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
pa_volume_t m = 0;
unsigned c, n;
pa_assert(a);
if (!cm)
return pa_cvolume_max(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;
if (a->values[c] > m)
m = a->values[c];
}
return m;
}
@ -590,11 +639,29 @@ pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) {
pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
pa_return_val_if_fail(max != (pa_volume_t) -1, NULL);
for (c = 0; c < v->channels; c++)
if (v->values[c] > t)
t = v->values[c];
t = pa_cvolume_max(v);
if (t <= 0)
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) (((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
return v;
}
pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map *cm, pa_channel_position_mask_t mask) {
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(max != (pa_volume_t) -1, NULL);
t = pa_cvolume_max_mask(v, cm, mask);
if (t <= PA_VOLUME_MUTED)
return pa_cvolume_set(v, v->channels, max);
for (c = 0; c < v->channels; c++)

View file

@ -178,9 +178,23 @@ char *pa_sw_volume_snprint_dB(char *s, size_t l, pa_volume_t v);
/** Return the average volume of all channels */
pa_volume_t pa_cvolume_avg(const pa_cvolume *a) PA_GCC_PURE;
/** Return the average volume of all channels that are included in the
* specified channel map with the specified channel position mask. If
* cm is NULL this call is identical to pa_cvolume_avg(). If no
* channel is selected the returned value will be
* PA_VOLUME_MUTED. \since 0.9.16 */
pa_volume_t pa_cvolume_avg_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) PA_GCC_PURE;
/** Return the maximum volume of all channels. \since 0.9.12 */
pa_volume_t pa_cvolume_max(const pa_cvolume *a) PA_GCC_PURE;
/** Return the maximum volume of all channels that are included in the
* specified channel map with the specified channel position mask. If
* cm is NULL this call is identical to pa_cvolume_max(). If no
* channel is selected the returned value will be PA_VOLUME_MUTED.
* \since 0.9.16 */
pa_volume_t pa_cvolume_max_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) PA_GCC_PURE;
/** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */
int pa_cvolume_valid(const pa_cvolume *v) PA_GCC_PURE;
@ -283,6 +297,12 @@ pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float
* volumes are kept. \since 0.9.15 */
pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max);
/** Scale the passed pa_cvolume structure so that the maximum volume
* of all channels selected via cm/mask equals max. This also modifies
* the volume of those channels that are unmasked. The proportions
* between the channel volumes are kept. \since 0.9.16 */
pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map *cm, pa_channel_position_mask_t mask);
/** Set the passed volume to all channels at the specified channel
* position. Will return the updated volume struct, or NULL if there
* is no channel at the position specified. You can check if a channel
@ -294,7 +314,7 @@ pa_cvolume* pa_cvolume_set_position(pa_cvolume *cv, const pa_channel_map *map, p
* position. Will return 0 if there is no channel at the position
* specified. You can check if a channel map includes a specific
* position by calling pa_channel_map_has_position(). \since 0.9.16 */
pa_volume_t pa_cvolume_get_position(pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t);
pa_volume_t pa_cvolume_get_position(pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) PA_GCC_PURE;
PA_C_DECL_END