#include <stdio.h>
#include <string.h>
-
-#include <pulse/i18n.h>
+#include <math.h>
#include <pulsecore/core-util.h>
+#include <pulsecore/i18n.h>
#include <pulsecore/macro.h>
#include <pulsecore/sample-util.h>
a->channels = 0;
for (c = 0; c < PA_CHANNELS_MAX; c++)
- a->values[c] = (pa_volume_t) -1;
+ a->values[c] = PA_VOLUME_INVALID;
return a;
}
int i;
pa_assert(a);
- pa_assert(channels > 0);
- pa_assert(channels <= PA_CHANNELS_MAX);
+ pa_assert(pa_channels_valid(channels));
a->channels = (uint8_t) channels;
for (i = 0; i < a->channels; i++)
- a->values[i] = v;
+ /* Clamp in case there is stale data that exceeds the current
+ * PA_VOLUME_MAX */
+ a->values[i] = PA_CLAMP_VOLUME(v);
return a;
}
}
pa_volume_t pa_cvolume_min(const pa_cvolume *a) {
- pa_volume_t m = (pa_volume_t) -1;
+ 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 (m == (pa_volume_t) -1 || a->values[c] < m)
+ 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 = PA_VOLUME_MUTED;
- unsigned c, n;
+ unsigned c;
pa_assert(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++) {
+ for (c = 0; c < a->channels; c++) {
if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
continue;
}
pa_volume_t pa_cvolume_min_mask(const pa_cvolume *a, const pa_channel_map *cm, pa_channel_position_mask_t mask) {
- pa_volume_t m = (pa_volume_t) -1;
- unsigned c, n;
+ pa_volume_t m = PA_VOLUME_MAX;
+ unsigned c;
pa_assert(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++) {
+ for (c = 0; c < a->channels; c++) {
if (!(PA_CHANNEL_POSITION_MASK(cm->map[c]) & mask))
continue;
- if (m == (pa_volume_t) -1 || a->values[c] < m)
+ if (a->values[c] < m)
m = a->values[c];
}
}
pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) {
- return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a) * pa_sw_volume_to_linear(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));
}
pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) {
- double v = pa_sw_volume_to_linear(b);
- if (v <= 0)
+ 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_sw_volume_from_linear(pa_sw_volume_to_linear(a) / v);
+ return (pa_volume_t) (((uint64_t) a * (uint64_t) PA_VOLUME_NORM + (uint64_t) b / 2ULL) / (uint64_t) b);
}
/* Amplitude, not power */
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;
* same volume value! That's why we need the lround() below!
*/
- return (pa_volume_t) lround(cbrt(v) * PA_VOLUME_NORM);
+ return (pa_volume_t) PA_CLAMP_VOLUME((uint64_t) lround(cbrt(v) * PA_VOLUME_NORM));
}
double pa_sw_volume_to_linear(pa_volume_t v) {
double f;
+ pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0.0);
+
if (v <= PA_VOLUME_MUTED)
return 0.0;
char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) {
unsigned channel;
- pa_bool_t first = TRUE;
+ bool first = true;
char *e;
pa_assert(s);
l -= pa_snprintf(e, l, "%s%u: %3u%%",
first ? "" : " ",
channel,
- (c->values[channel]*100)/PA_VOLUME_NORM);
+ (c->values[channel]*100+PA_VOLUME_NORM/2)/PA_VOLUME_NORM);
e = strchr(e, 0);
- first = FALSE;
+ first = false;
}
return s;
pa_init_i18n();
- if (v == (pa_volume_t) -1) {
+ if (!PA_VOLUME_IS_VALID(v)) {
pa_snprintf(s, l, _("(invalid)"));
return s;
}
- pa_snprintf(s, l, "%3u%%", (v*100)/PA_VOLUME_NORM);
+ pa_snprintf(s, l, "%3u%%", (v*100+PA_VOLUME_NORM/2)/PA_VOLUME_NORM);
return s;
}
char *pa_sw_cvolume_snprint_dB(char *s, size_t l, const pa_cvolume *c) {
unsigned channel;
- pa_bool_t first = TRUE;
+ bool first = true;
char *e;
pa_assert(s);
isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
e = strchr(e, 0);
- first = FALSE;
+ first = false;
+ }
+
+ return s;
+}
+
+char *pa_cvolume_snprint_verbose(char *s, size_t l, const pa_cvolume *c, const pa_channel_map *map, int print_dB) {
+ char *current = s;
+ bool first = true;
+
+ pa_assert(s);
+ pa_assert(l > 0);
+ pa_assert(c);
+
+ pa_init_i18n();
+
+ if (!pa_cvolume_valid(c)) {
+ pa_snprintf(s, l, _("(invalid)"));
+ return s;
+ }
+
+ pa_assert(!map || (map->channels == c->channels));
+ pa_assert(!map || pa_channel_map_valid(map));
+
+ current[0] = 0;
+
+ for (unsigned channel = 0; channel < c->channels && l > 1; channel++) {
+ char channel_position[32];
+ size_t bytes_printed;
+ char buf[PA_VOLUME_SNPRINT_VERBOSE_MAX];
+
+ if (map)
+ pa_snprintf(channel_position, sizeof(channel_position), "%s", pa_channel_position_to_string(map->map[channel]));
+ else
+ pa_snprintf(channel_position, sizeof(channel_position), "%u", channel);
+
+ bytes_printed = pa_snprintf(current, l, "%s%s: %s",
+ first ? "" : ", ",
+ channel_position,
+ pa_volume_snprint_verbose(buf, sizeof(buf), c->values[channel], print_dB));
+ l -= bytes_printed;
+ current += bytes_printed;
+ first = false;
}
return s;
pa_init_i18n();
- if (v == (pa_volume_t) -1) {
+ if (!PA_VOLUME_IS_VALID(v)) {
pa_snprintf(s, l, _("(invalid)"));
return s;
}
f = pa_sw_volume_to_dB(v);
- pa_snprintf(s, l, "%0.2f dB",
- isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
+ pa_snprintf(s, l, "%0.2f dB", isinf(f) < 0 || f <= PA_DECIBEL_MININFTY ? -INFINITY : f);
+
+ return s;
+}
+
+char *pa_volume_snprint_verbose(char *s, size_t l, pa_volume_t v, int print_dB) {
+ char dB[PA_SW_VOLUME_SNPRINT_DB_MAX];
+
+ pa_assert(s);
+ pa_assert(l > 0);
+
+ pa_init_i18n();
+
+ if (!PA_VOLUME_IS_VALID(v)) {
+ pa_snprintf(s, l, _("(invalid)"));
+ return s;
+ }
+
+ pa_snprintf(s, l, "%" PRIu32 " / %3u%%%s%s",
+ v,
+ (v * 100 + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM,
+ print_dB ? " / " : "",
+ print_dB ? pa_sw_volume_snprint_dB(dB, sizeof(dB), v) : "");
return s;
}
unsigned c;
pa_assert(a);
- pa_return_val_if_fail(pa_cvolume_valid(a), 0);
+ if (pa_cvolume_valid(a) == 0)
+ abort();
+
+ /* 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)
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_multiply(a->values[i], b);
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);
pa_assert(v);
- if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX)
+ if (!pa_channels_valid(v->channels))
return 0;
for (c = 0; c < v->channels; c++)
- if (v->values[c] == (pa_volume_t) -1)
+ if (!PA_VOLUME_IS_VALID(v->values[c]))
return 0;
return 1;
}
-static pa_bool_t on_left(pa_channel_position_t p) {
+static bool on_left(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT);
}
-static pa_bool_t on_right(pa_channel_position_t p) {
+static bool on_right(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT);
}
-static pa_bool_t on_center(pa_channel_position_t p) {
+static bool on_center(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
}
-static pa_bool_t on_lfe(pa_channel_position_t p) {
+static bool on_lfe(pa_channel_position_t p) {
return p == PA_CHANNEL_POSITION_LFE;
}
-static pa_bool_t on_front(pa_channel_position_t p) {
+static bool on_front(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT);
}
-static pa_bool_t on_rear(pa_channel_position_t p) {
+static bool on_rear(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
}
pa_assert(from);
pa_assert(to);
- pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
- pa_return_val_if_fail(pa_channel_map_valid(from), NULL);
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);
pa_assert(v);
pa_assert(map);
- pa_return_val_if_fail(pa_cvolume_valid(v), 0.0f);
- pa_return_val_if_fail(pa_channel_map_valid(map), 0.0f);
pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
if (!pa_channel_map_can_balance(map))
pa_assert(map);
pa_assert(v);
- pa_assert(new_balance >= -1.0f);
- pa_assert(new_balance <= 1.0f);
- pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
- pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
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;
m = PA_MAX(left, right);
if (new_balance <= 0) {
- nright = (new_balance + 1.0f) * m;
+ nright = (new_balance + 1.0f) * m;
nleft = m;
- } else {
+ } else {
nleft = (1.0f - new_balance) * m;
nright = m;
}
if (left == 0)
v->values[c] = nleft;
else
- v->values[c] = (pa_volume_t) (((uint64_t) v->values[c] * (uint64_t) nleft) / (uint64_t) left);
+ 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) (((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right);
+ v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nright) / (uint64_t) right);
}
}
pa_assert(v);
pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
- pa_return_val_if_fail(max != (pa_volume_t) -1, NULL);
+ pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL);
t = pa_cvolume_max(v);
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);
+ v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
return v;
}
pa_assert(v);
- pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
- pa_return_val_if_fail(max != (pa_volume_t) -1, NULL);
+ pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL);
+
+ if (!cm)
+ return pa_cvolume_scale(v, max);
+
+ pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL);
t = pa_cvolume_max_mask(v, cm, mask);
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);
+ v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t);
return v;
}
pa_assert(v);
pa_assert(map);
- pa_return_val_if_fail(pa_cvolume_valid(v), 0.0f);
- pa_return_val_if_fail(pa_channel_map_valid(map), 0.0f);
pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, map), 0.0f);
if (!pa_channel_map_can_fade(map))
pa_assert(map);
pa_assert(v);
- pa_assert(new_fade >= -1.0f);
- pa_assert(new_fade <= 1.0f);
- pa_return_val_if_fail(pa_cvolume_valid(v), NULL);
- pa_return_val_if_fail(pa_channel_map_valid(map), NULL);
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;
m = PA_MAX(front, rear);
if (new_fade <= 0) {
- nfront = (new_fade + 1.0f) * m;
+ nfront = (new_fade + 1.0f) * m;
nrear = m;
- } else {
+ } else {
nrear = (1.0f - new_fade) * m;
nfront = m;
}
if (front == 0)
v->values[c] = nfront;
else
- v->values[c] = (pa_volume_t) (((uint64_t) v->values[c] * (uint64_t) nfront) / (uint64_t) front);
+ 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) (((uint64_t) v->values[c] * (uint64_t) nrear) / (uint64_t) rear);
+ v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) nrear) / (uint64_t) rear);
}
}
pa_volume_t v) {
unsigned c;
- pa_bool_t good = FALSE;
+ bool good = false;
pa_assert(cv);
pa_assert(map);
pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), NULL);
pa_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, NULL);
+ pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), NULL);
for (c = 0; c < map->channels; c++)
if (map->map[c] == t) {
cv->values[c] = v;
- good = TRUE;
+ good = true;
}
return good ? cv : NULL;
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);
+}
+
+pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc) {
+ return pa_cvolume_inc_clamp(v, inc, PA_VOLUME_MAX);
+}
+
+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);
+}
+
+int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b) {
+ int i;
+ pa_assert(a);
+ pa_assert(b);
+
+ if (PA_UNLIKELY(a == b))
+ return 1;
+
+ if (a->channels != b->channels)
+ return 0;
+
+ for (i = 0; i < a->channels; i++) {
+ if (a->ramps[i].type != b->ramps[i].type ||
+ a->ramps[i].length != b->ramps[i].length ||
+ a->ramps[i].target != b->ramps[i].target)
+ return 0;
+ }
+
+ return 1;
+}
+
+pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp) {
+ unsigned c;
+
+ pa_assert(ramp);
+
+ ramp->channels = 0;
+
+ for (c = 0; c < PA_CHANNELS_MAX; c++) {
+ ramp->ramps[c].type = PA_VOLUME_RAMP_TYPE_LINEAR;
+ ramp->ramps[c].length = 0;
+ ramp->ramps[c].target = PA_VOLUME_INVALID;
+ }
+
+ return ramp;
+}
+
+pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channels, pa_volume_ramp_type_t type, long time, pa_volume_t vol) {
+ int i;
+
+ pa_assert(ramp);
+ pa_assert(channels > 0);
+ pa_assert(time >= 0);
+ pa_assert(channels <= PA_CHANNELS_MAX);
+
+ ramp->channels = (uint8_t) channels;
+
+ for (i = 0; i < ramp->channels; i++) {
+ ramp->ramps[i].type = type;
+ ramp->ramps[i].length = time;
+ ramp->ramps[i].target = PA_CLAMP_VOLUME(vol);
+ }
+
+ return ramp;
+}
+
+pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol) {
+
+ pa_assert(ramp);
+ pa_assert(channel <= ramp->channels);
+ pa_assert(time >= 0);
+
+ ramp->ramps[channel].type = type;
+ ramp->ramps[channel].length = time;
+ ramp->ramps[channel].target = PA_CLAMP_VOLUME(vol);
+
+ return ramp;
+}