static void set_from_pa_map (GvcChannelMap *map, const pa_channel_map *pa_map) { g_assert (pa_channel_map_valid(pa_map)); map->priv->can_balance = pa_channel_map_can_balance (pa_map); map->priv->can_fade = pa_channel_map_can_fade (pa_map); map->priv->pa_map = *pa_map; pa_cvolume_set(&map->priv->pa_volume, pa_map->channels, PA_VOLUME_NORM); }
pa_cvolume* pa_cvolume_set_fade(pa_cvolume *v, const pa_channel_map *map, float new_fade) { 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; return set_balance(v, map, new_fade, on_rear, on_front); }
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; }
float pa_cvolume_get_fade(const pa_cvolume *v, const pa_channel_map *map) { pa_volume_t front, rear; 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_fade(map)) return 0.0f; get_avg_fr(map, v, &front, &rear); if (front == rear) return 0.0f; if (rear > front) return -1.0f + ((float) front / (float) rear); else return 1.0f - ((float) rear / (float) front); }
static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_input_new_data *data, struct userdata *u) { const char *hpos, *vpos, *role, *id; double f; char t[PA_CVOLUME_SNPRINT_MAX]; pa_cvolume v; pa_assert(data); if (!(role = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_ROLE))) return PA_HOOK_OK; if (!pa_streq(role, "event")) return PA_HOOK_OK; if ((id = pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID))) { /* The test sounds should never be positioned in space, since * they might be triggered themselves to configure the speakers * in space, which we don't want to mess up. */ if (pa_startswith(id, "audio-channel-")) return PA_HOOK_OK; if (pa_streq(id, "audio-volume-change")) return PA_HOOK_OK; if (pa_streq(id, "audio-test-signal")) return PA_HOOK_OK; } if (!(hpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_HPOS))) hpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_HPOS); if (!(vpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_VPOS))) vpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_VPOS); if (!hpos && !vpos) return PA_HOOK_OK; pa_cvolume_reset(&v, data->sink->sample_spec.channels); if (hpos) { if (parse_pos(hpos, &f) < 0) return PA_HOOK_OK; if (pa_channel_map_can_balance(&data->sink->channel_map)) { pa_log_debug("Positioning event sound '%s' horizontally at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); pa_cvolume_set_balance(&v, &data->sink->channel_map, f*2.0-1.0); } } if (vpos) { if (parse_pos(vpos, &f) < 0) return PA_HOOK_OK; if (pa_channel_map_can_fade(&data->sink->channel_map)) { pa_log_debug("Positioning event sound '%s' vertically at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f); pa_cvolume_set_fade(&v, &data->sink->channel_map, f*2.0-1.0); } } pa_log_debug("Final volume factor %s.", pa_cvolume_snprint(t, sizeof(t), &v)); pa_sink_input_new_data_add_volume_factor_sink(data, u->name, &v); return PA_HOOK_OK; }