153a5a1b3Sopenharmony_ci#!/usr/bin/python
253a5a1b3Sopenharmony_ci
353a5a1b3Sopenharmony_ciimport pygtk, gtk, sys
453a5a1b3Sopenharmony_cifrom ctypes import *
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_citry:
753a5a1b3Sopenharmony_ci    libpulse = cdll.LoadLibrary("../.libs/libpulse.so")
853a5a1b3Sopenharmony_ciexcept OSError:
953a5a1b3Sopenharmony_ci    try:
1053a5a1b3Sopenharmony_ci        libpulse = cdll.LoadLibrary(".libs/libpulse.so")
1153a5a1b3Sopenharmony_ci    except OSError:
1253a5a1b3Sopenharmony_ci        libpulse = cdll.LoadLibrary("libpulse.so")
1353a5a1b3Sopenharmony_ci
1453a5a1b3Sopenharmony_ciclass ChannelMap(Structure):
1553a5a1b3Sopenharmony_ci    _fields_ = [("channels", c_ubyte),
1653a5a1b3Sopenharmony_ci                ("map", c_uint * 32)]
1753a5a1b3Sopenharmony_ci
1853a5a1b3Sopenharmony_ci    _to_name = libpulse.pa_channel_map_to_name
1953a5a1b3Sopenharmony_ci    _to_name.restype = c_char_p
2053a5a1b3Sopenharmony_ci    _to_name.argtypes = [c_void_p]
2153a5a1b3Sopenharmony_ci
2253a5a1b3Sopenharmony_ci    _to_pretty_name = libpulse.pa_channel_map_to_pretty_name
2353a5a1b3Sopenharmony_ci    _to_pretty_name.restype = c_char_p
2453a5a1b3Sopenharmony_ci    _to_pretty_name.argtypes = [c_void_p]
2553a5a1b3Sopenharmony_ci
2653a5a1b3Sopenharmony_ci    _snprint = libpulse.pa_channel_map_snprint
2753a5a1b3Sopenharmony_ci    _snprint.restype = c_char_p
2853a5a1b3Sopenharmony_ci    _snprint.argtypes = [c_char_p, c_ulong, c_void_p]
2953a5a1b3Sopenharmony_ci
3053a5a1b3Sopenharmony_ci    _position_to_string = libpulse.pa_channel_position_to_string
3153a5a1b3Sopenharmony_ci    _position_to_string.restype = c_char_p
3253a5a1b3Sopenharmony_ci    _position_to_string.argtypes = [c_uint]
3353a5a1b3Sopenharmony_ci
3453a5a1b3Sopenharmony_ci    _position_to_pretty_string = libpulse.pa_channel_position_to_pretty_string
3553a5a1b3Sopenharmony_ci    _position_to_pretty_string.restype = c_char_p
3653a5a1b3Sopenharmony_ci    _position_to_pretty_string.argtypes = [c_uint]
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_ci    _can_balance = libpulse.pa_channel_map_can_balance
3953a5a1b3Sopenharmony_ci    _can_balance.restype = c_int
4053a5a1b3Sopenharmony_ci    _can_balance.argtypes = [c_void_p]
4153a5a1b3Sopenharmony_ci
4253a5a1b3Sopenharmony_ci    _can_fade = libpulse.pa_channel_map_can_fade
4353a5a1b3Sopenharmony_ci    _can_fade.restype = c_int
4453a5a1b3Sopenharmony_ci    _can_fade.argtypes = [c_void_p]
4553a5a1b3Sopenharmony_ci
4653a5a1b3Sopenharmony_ci    _parse = libpulse.pa_channel_map_parse
4753a5a1b3Sopenharmony_ci    _parse.restype = c_void_p
4853a5a1b3Sopenharmony_ci    _parse.argtypes = [c_void_p, c_char_p]
4953a5a1b3Sopenharmony_ci
5053a5a1b3Sopenharmony_ci    def to_name(this):
5153a5a1b3Sopenharmony_ci        return this._to_name(byref(this))
5253a5a1b3Sopenharmony_ci
5353a5a1b3Sopenharmony_ci    def to_pretty_name(this):
5453a5a1b3Sopenharmony_ci        return this._to_pretty_name(byref(this))
5553a5a1b3Sopenharmony_ci
5653a5a1b3Sopenharmony_ci    def snprint(this):
5753a5a1b3Sopenharmony_ci        s = create_string_buffer(336)
5853a5a1b3Sopenharmony_ci        r = this._snprint(s, len(s), byref(this))
5953a5a1b3Sopenharmony_ci
6053a5a1b3Sopenharmony_ci        if r is None:
6153a5a1b3Sopenharmony_ci            return None
6253a5a1b3Sopenharmony_ci        else:
6353a5a1b3Sopenharmony_ci            return s.value
6453a5a1b3Sopenharmony_ci
6553a5a1b3Sopenharmony_ci    def position_to_string(this, pos):
6653a5a1b3Sopenharmony_ci        return this._position_to_string(pos)
6753a5a1b3Sopenharmony_ci
6853a5a1b3Sopenharmony_ci    def position_to_pretty_string(this, pos):
6953a5a1b3Sopenharmony_ci        return this._position_to_pretty_string(pos)
7053a5a1b3Sopenharmony_ci
7153a5a1b3Sopenharmony_ci    def can_balance(this):
7253a5a1b3Sopenharmony_ci        return bool(this._can_balance(byref(this)))
7353a5a1b3Sopenharmony_ci
7453a5a1b3Sopenharmony_ci    def can_fade(this):
7553a5a1b3Sopenharmony_ci        return bool(this._can_fade(byref(this)))
7653a5a1b3Sopenharmony_ci
7753a5a1b3Sopenharmony_ci    def parse(this, s):
7853a5a1b3Sopenharmony_ci        if this._parse(byref(this), s) is None:
7953a5a1b3Sopenharmony_ci            raise Exception("Parse failure")
8053a5a1b3Sopenharmony_ci
8153a5a1b3Sopenharmony_ci
8253a5a1b3Sopenharmony_ciclass CVolume(Structure):
8353a5a1b3Sopenharmony_ci    _fields_ = [("channels", c_ubyte),
8453a5a1b3Sopenharmony_ci                ("values", c_uint32 * 32)]
8553a5a1b3Sopenharmony_ci
8653a5a1b3Sopenharmony_ci    _snprint = libpulse.pa_cvolume_snprint
8753a5a1b3Sopenharmony_ci    _snprint.restype = c_char_p
8853a5a1b3Sopenharmony_ci    _snprint.argtypes = [c_char_p, c_ulong, c_void_p]
8953a5a1b3Sopenharmony_ci
9053a5a1b3Sopenharmony_ci    _max = libpulse.pa_cvolume_max
9153a5a1b3Sopenharmony_ci    _max.restype = c_uint32
9253a5a1b3Sopenharmony_ci    _max.argtypes = [c_void_p]
9353a5a1b3Sopenharmony_ci
9453a5a1b3Sopenharmony_ci    _scale = libpulse.pa_cvolume_scale
9553a5a1b3Sopenharmony_ci    _scale.restype = c_void_p
9653a5a1b3Sopenharmony_ci    _scale.argtypes = [c_void_p, c_uint32]
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_ci    _get_balance = libpulse.pa_cvolume_get_balance
9953a5a1b3Sopenharmony_ci    _get_balance.restype = c_float
10053a5a1b3Sopenharmony_ci    _get_balance.argtypes = [c_void_p, c_void_p]
10153a5a1b3Sopenharmony_ci
10253a5a1b3Sopenharmony_ci    _get_fade = libpulse.pa_cvolume_get_fade
10353a5a1b3Sopenharmony_ci    _get_fade.restype = c_float
10453a5a1b3Sopenharmony_ci    _get_fade.argtypes = [c_void_p, c_void_p]
10553a5a1b3Sopenharmony_ci
10653a5a1b3Sopenharmony_ci    _set_balance = libpulse.pa_cvolume_set_balance
10753a5a1b3Sopenharmony_ci    _set_balance.restype = c_void_p
10853a5a1b3Sopenharmony_ci    _set_balance.argtypes = [c_void_p, c_void_p, c_float]
10953a5a1b3Sopenharmony_ci
11053a5a1b3Sopenharmony_ci    _set_fade = libpulse.pa_cvolume_set_fade
11153a5a1b3Sopenharmony_ci    _set_fade.restype = c_void_p
11253a5a1b3Sopenharmony_ci    _set_fade.argtypes = [c_void_p, c_void_p, c_float]
11353a5a1b3Sopenharmony_ci
11453a5a1b3Sopenharmony_ci    _to_dB = libpulse.pa_sw_volume_to_dB
11553a5a1b3Sopenharmony_ci    _to_dB.restype = c_double
11653a5a1b3Sopenharmony_ci    _to_dB.argytpes = [c_uint32]
11753a5a1b3Sopenharmony_ci
11853a5a1b3Sopenharmony_ci    def snprint(this):
11953a5a1b3Sopenharmony_ci        s = create_string_buffer(320)
12053a5a1b3Sopenharmony_ci        r = this._snprint(s, len(s), byref(this))
12153a5a1b3Sopenharmony_ci
12253a5a1b3Sopenharmony_ci        if r is None:
12353a5a1b3Sopenharmony_ci            return None
12453a5a1b3Sopenharmony_ci        else:
12553a5a1b3Sopenharmony_ci            return s.raw
12653a5a1b3Sopenharmony_ci
12753a5a1b3Sopenharmony_ci    def max(this):
12853a5a1b3Sopenharmony_ci        return this._max(byref(this))
12953a5a1b3Sopenharmony_ci
13053a5a1b3Sopenharmony_ci    def scale(this, v):
13153a5a1b3Sopenharmony_ci        return this._scale(byref(this), v)
13253a5a1b3Sopenharmony_ci
13353a5a1b3Sopenharmony_ci    def get_balance(this, cm):
13453a5a1b3Sopenharmony_ci        return this._get_balance(byref(this), byref(cm))
13553a5a1b3Sopenharmony_ci
13653a5a1b3Sopenharmony_ci    def get_fade(this, cm):
13753a5a1b3Sopenharmony_ci        return this._get_fade(byref(this), byref(cm))
13853a5a1b3Sopenharmony_ci
13953a5a1b3Sopenharmony_ci    def set_balance(this, cm, f):
14053a5a1b3Sopenharmony_ci        return this._set_balance(byref(this), byref(cm), f)
14153a5a1b3Sopenharmony_ci
14253a5a1b3Sopenharmony_ci    def set_fade(this, cm, f):
14353a5a1b3Sopenharmony_ci        return this._set_fade(byref(this), byref(cm), f)
14453a5a1b3Sopenharmony_ci
14553a5a1b3Sopenharmony_ci    def to_dB(this, channel = None):
14653a5a1b3Sopenharmony_ci        if channel is None:
14753a5a1b3Sopenharmony_ci            return this._to_dB(this.max())
14853a5a1b3Sopenharmony_ci
14953a5a1b3Sopenharmony_ci        return this._to_dB(this.values[channel])
15053a5a1b3Sopenharmony_ci
15153a5a1b3Sopenharmony_cicm = ChannelMap()
15253a5a1b3Sopenharmony_ci
15353a5a1b3Sopenharmony_ciif len(sys.argv) > 1:
15453a5a1b3Sopenharmony_ci    cm.parse(sys.argv[1])
15553a5a1b3Sopenharmony_cielse:
15653a5a1b3Sopenharmony_ci    cm.parse("surround-51")
15753a5a1b3Sopenharmony_ci
15853a5a1b3Sopenharmony_civ = CVolume()
15953a5a1b3Sopenharmony_civ.channels = cm.channels
16053a5a1b3Sopenharmony_ci
16153a5a1b3Sopenharmony_cifor i in range(cm.channels):
16253a5a1b3Sopenharmony_ci    v.values[i] = 65536
16353a5a1b3Sopenharmony_ci
16453a5a1b3Sopenharmony_cititle = cm.to_pretty_name()
16553a5a1b3Sopenharmony_ciif title is None:
16653a5a1b3Sopenharmony_ci    title = cm.snprint()
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_ciwindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
16953a5a1b3Sopenharmony_ciwindow.set_title(unicode(title))
17053a5a1b3Sopenharmony_ciwindow.set_border_width(12)
17153a5a1b3Sopenharmony_ci
17253a5a1b3Sopenharmony_civbox = gtk.VBox(spacing=6)
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_cichannel_labels = {}
17553a5a1b3Sopenharmony_cichannel_scales = {}
17653a5a1b3Sopenharmony_cichannel_dB_labels = {}
17753a5a1b3Sopenharmony_ci
17853a5a1b3Sopenharmony_cidef update_volume(update_channels = True, update_fade = True, update_balance = True, update_scale = True):
17953a5a1b3Sopenharmony_ci    if update_channels:
18053a5a1b3Sopenharmony_ci        for i in range(cm.channels):
18153a5a1b3Sopenharmony_ci            channel_scales[i].set_value(v.values[i])
18253a5a1b3Sopenharmony_ci
18353a5a1b3Sopenharmony_ci    if update_scale:
18453a5a1b3Sopenharmony_ci        value_scale.set_value(v.max())
18553a5a1b3Sopenharmony_ci
18653a5a1b3Sopenharmony_ci    if update_balance:
18753a5a1b3Sopenharmony_ci        balance_scale.set_value(v.get_balance(cm))
18853a5a1b3Sopenharmony_ci
18953a5a1b3Sopenharmony_ci    if update_fade:
19053a5a1b3Sopenharmony_ci        fade_scale.set_value(v.get_fade(cm))
19153a5a1b3Sopenharmony_ci
19253a5a1b3Sopenharmony_ci    for i in range(cm.channels):
19353a5a1b3Sopenharmony_ci        channel_dB_labels[i].set_label("%0.2f dB" % v.to_dB(i))
19453a5a1b3Sopenharmony_ci
19553a5a1b3Sopenharmony_ci    value_dB_label.set_label("%0.2f dB" % v.to_dB())
19653a5a1b3Sopenharmony_ci
19753a5a1b3Sopenharmony_cidef fade_value_changed(fs):
19853a5a1b3Sopenharmony_ci    v.set_fade(cm, fade_scale.get_value())
19953a5a1b3Sopenharmony_ci    update_volume(update_fade = False)
20053a5a1b3Sopenharmony_ci
20153a5a1b3Sopenharmony_cidef balance_value_changed(fs):
20253a5a1b3Sopenharmony_ci    v.set_balance(cm, balance_scale.get_value())
20353a5a1b3Sopenharmony_ci    update_volume(update_balance = False)
20453a5a1b3Sopenharmony_ci
20553a5a1b3Sopenharmony_cidef value_value_changed(fs):
20653a5a1b3Sopenharmony_ci    v.scale(int(value_scale.get_value()))
20753a5a1b3Sopenharmony_ci    update_volume(update_scale = False)
20853a5a1b3Sopenharmony_ci
20953a5a1b3Sopenharmony_cidef channel_value_changed(fs, i):
21053a5a1b3Sopenharmony_ci    v.values[i] = int(channel_scales[i].get_value())
21153a5a1b3Sopenharmony_ci    update_volume(update_channels = False)
21253a5a1b3Sopenharmony_ci
21353a5a1b3Sopenharmony_cifor i in range(cm.channels):
21453a5a1b3Sopenharmony_ci    channel_labels[i] = gtk.Label(cm.position_to_pretty_string(cm.map[i]))
21553a5a1b3Sopenharmony_ci    channel_labels[i].set_alignment(0, 1)
21653a5a1b3Sopenharmony_ci    vbox.pack_start(channel_labels[i], expand=False, fill=True)
21753a5a1b3Sopenharmony_ci
21853a5a1b3Sopenharmony_ci    channel_scales[i] = gtk.HScale()
21953a5a1b3Sopenharmony_ci    channel_scales[i].set_range(0, 65536*3/2)
22053a5a1b3Sopenharmony_ci    channel_scales[i].set_digits(0)
22153a5a1b3Sopenharmony_ci    channel_scales[i].set_value_pos(gtk.POS_RIGHT)
22253a5a1b3Sopenharmony_ci    vbox.pack_start(channel_scales[i], expand=False, fill=True)
22353a5a1b3Sopenharmony_ci
22453a5a1b3Sopenharmony_ci    channel_dB_labels[i] = gtk.Label("-xxx dB")
22553a5a1b3Sopenharmony_ci    channel_dB_labels[i].set_alignment(1, 1)
22653a5a1b3Sopenharmony_ci    vbox.pack_start(channel_dB_labels[i], expand=False, fill=True)
22753a5a1b3Sopenharmony_ci
22853a5a1b3Sopenharmony_civalue_label = gtk.Label("Value")
22953a5a1b3Sopenharmony_civalue_label.set_alignment(0, .5)
23053a5a1b3Sopenharmony_civbox.pack_start(value_label, expand=False, fill=True)
23153a5a1b3Sopenharmony_civalue_scale = gtk.HScale()
23253a5a1b3Sopenharmony_civalue_scale.set_range(0, 65536*3/2)
23353a5a1b3Sopenharmony_civalue_scale.set_value_pos(gtk.POS_RIGHT)
23453a5a1b3Sopenharmony_civalue_scale.set_digits(0)
23553a5a1b3Sopenharmony_civbox.pack_start(value_scale, expand=False, fill=True)
23653a5a1b3Sopenharmony_civalue_dB_label = gtk.Label("-xxx dB")
23753a5a1b3Sopenharmony_civalue_dB_label.set_alignment(1, 1)
23853a5a1b3Sopenharmony_civbox.pack_start(value_dB_label, expand=False, fill=True)
23953a5a1b3Sopenharmony_ci
24053a5a1b3Sopenharmony_cibalance_label = gtk.Label("Balance")
24153a5a1b3Sopenharmony_cibalance_label.set_alignment(0, .5)
24253a5a1b3Sopenharmony_civbox.pack_start(balance_label, expand=False, fill=True)
24353a5a1b3Sopenharmony_cibalance_scale = gtk.HScale()
24453a5a1b3Sopenharmony_cibalance_scale.set_range(-1.0, +1.0)
24553a5a1b3Sopenharmony_cibalance_scale.set_value_pos(gtk.POS_RIGHT)
24653a5a1b3Sopenharmony_cibalance_scale.set_digits(2)
24753a5a1b3Sopenharmony_civbox.pack_start(balance_scale, expand=False, fill=True)
24853a5a1b3Sopenharmony_ci
24953a5a1b3Sopenharmony_cifade_label = gtk.Label("Fade")
25053a5a1b3Sopenharmony_cifade_label.set_alignment(0, .5)
25153a5a1b3Sopenharmony_civbox.pack_start(fade_label, expand=False, fill=True)
25253a5a1b3Sopenharmony_cifade_scale = gtk.HScale()
25353a5a1b3Sopenharmony_cifade_scale.set_range(-1.0, +1.0)
25453a5a1b3Sopenharmony_cifade_scale.set_value_pos(gtk.POS_RIGHT)
25553a5a1b3Sopenharmony_cifade_scale.set_digits(2)
25653a5a1b3Sopenharmony_civbox.pack_start(fade_scale, expand=False, fill=True)
25753a5a1b3Sopenharmony_ci
25853a5a1b3Sopenharmony_ciwindow.add(vbox)
25953a5a1b3Sopenharmony_ciwindow.set_default_size(600, 50)
26053a5a1b3Sopenharmony_ci
26153a5a1b3Sopenharmony_ciupdate_volume()
26253a5a1b3Sopenharmony_ci
26353a5a1b3Sopenharmony_cifor i in range(cm.channels):
26453a5a1b3Sopenharmony_ci    channel_scales[i].connect("value_changed", channel_value_changed, i)
26553a5a1b3Sopenharmony_cifade_scale.connect("value_changed", fade_value_changed)
26653a5a1b3Sopenharmony_cibalance_scale.connect("value_changed", balance_value_changed)
26753a5a1b3Sopenharmony_civalue_scale.connect("value_changed", value_value_changed)
26853a5a1b3Sopenharmony_ci
26953a5a1b3Sopenharmony_civbox.show_all()
27053a5a1b3Sopenharmony_ci
27153a5a1b3Sopenharmony_ciif not cm.can_balance():
27253a5a1b3Sopenharmony_ci    balance_label.hide()
27353a5a1b3Sopenharmony_ci    balance_scale.hide()
27453a5a1b3Sopenharmony_ci
27553a5a1b3Sopenharmony_ciif not cm.can_fade():
27653a5a1b3Sopenharmony_ci    fade_label.hide()
27753a5a1b3Sopenharmony_ci    fade_scale.hide()
27853a5a1b3Sopenharmony_ci
27953a5a1b3Sopenharmony_ci
28053a5a1b3Sopenharmony_ciwindow.show()
28153a5a1b3Sopenharmony_ci
28253a5a1b3Sopenharmony_cigtk.main()
283