• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python
2
3import pygtk, gtk, sys
4from ctypes import *
5
6try:
7    libpulse = cdll.LoadLibrary("../.libs/libpulse.so")
8except OSError:
9    try:
10        libpulse = cdll.LoadLibrary(".libs/libpulse.so")
11    except OSError:
12        libpulse = cdll.LoadLibrary("libpulse.so")
13
14class ChannelMap(Structure):
15    _fields_ = [("channels", c_ubyte),
16                ("map", c_uint * 32)]
17
18    _to_name = libpulse.pa_channel_map_to_name
19    _to_name.restype = c_char_p
20    _to_name.argtypes = [c_void_p]
21
22    _to_pretty_name = libpulse.pa_channel_map_to_pretty_name
23    _to_pretty_name.restype = c_char_p
24    _to_pretty_name.argtypes = [c_void_p]
25
26    _snprint = libpulse.pa_channel_map_snprint
27    _snprint.restype = c_char_p
28    _snprint.argtypes = [c_char_p, c_ulong, c_void_p]
29
30    _position_to_string = libpulse.pa_channel_position_to_string
31    _position_to_string.restype = c_char_p
32    _position_to_string.argtypes = [c_uint]
33
34    _position_to_pretty_string = libpulse.pa_channel_position_to_pretty_string
35    _position_to_pretty_string.restype = c_char_p
36    _position_to_pretty_string.argtypes = [c_uint]
37
38    _can_balance = libpulse.pa_channel_map_can_balance
39    _can_balance.restype = c_int
40    _can_balance.argtypes = [c_void_p]
41
42    _can_fade = libpulse.pa_channel_map_can_fade
43    _can_fade.restype = c_int
44    _can_fade.argtypes = [c_void_p]
45
46    _parse = libpulse.pa_channel_map_parse
47    _parse.restype = c_void_p
48    _parse.argtypes = [c_void_p, c_char_p]
49
50    def to_name(this):
51        return this._to_name(byref(this))
52
53    def to_pretty_name(this):
54        return this._to_pretty_name(byref(this))
55
56    def snprint(this):
57        s = create_string_buffer(336)
58        r = this._snprint(s, len(s), byref(this))
59
60        if r is None:
61            return None
62        else:
63            return s.value
64
65    def position_to_string(this, pos):
66        return this._position_to_string(pos)
67
68    def position_to_pretty_string(this, pos):
69        return this._position_to_pretty_string(pos)
70
71    def can_balance(this):
72        return bool(this._can_balance(byref(this)))
73
74    def can_fade(this):
75        return bool(this._can_fade(byref(this)))
76
77    def parse(this, s):
78        if this._parse(byref(this), s) is None:
79            raise Exception("Parse failure")
80
81
82class CVolume(Structure):
83    _fields_ = [("channels", c_ubyte),
84                ("values", c_uint32 * 32)]
85
86    _snprint = libpulse.pa_cvolume_snprint
87    _snprint.restype = c_char_p
88    _snprint.argtypes = [c_char_p, c_ulong, c_void_p]
89
90    _max = libpulse.pa_cvolume_max
91    _max.restype = c_uint32
92    _max.argtypes = [c_void_p]
93
94    _scale = libpulse.pa_cvolume_scale
95    _scale.restype = c_void_p
96    _scale.argtypes = [c_void_p, c_uint32]
97
98    _get_balance = libpulse.pa_cvolume_get_balance
99    _get_balance.restype = c_float
100    _get_balance.argtypes = [c_void_p, c_void_p]
101
102    _get_fade = libpulse.pa_cvolume_get_fade
103    _get_fade.restype = c_float
104    _get_fade.argtypes = [c_void_p, c_void_p]
105
106    _set_balance = libpulse.pa_cvolume_set_balance
107    _set_balance.restype = c_void_p
108    _set_balance.argtypes = [c_void_p, c_void_p, c_float]
109
110    _set_fade = libpulse.pa_cvolume_set_fade
111    _set_fade.restype = c_void_p
112    _set_fade.argtypes = [c_void_p, c_void_p, c_float]
113
114    _to_dB = libpulse.pa_sw_volume_to_dB
115    _to_dB.restype = c_double
116    _to_dB.argytpes = [c_uint32]
117
118    def snprint(this):
119        s = create_string_buffer(320)
120        r = this._snprint(s, len(s), byref(this))
121
122        if r is None:
123            return None
124        else:
125            return s.raw
126
127    def max(this):
128        return this._max(byref(this))
129
130    def scale(this, v):
131        return this._scale(byref(this), v)
132
133    def get_balance(this, cm):
134        return this._get_balance(byref(this), byref(cm))
135
136    def get_fade(this, cm):
137        return this._get_fade(byref(this), byref(cm))
138
139    def set_balance(this, cm, f):
140        return this._set_balance(byref(this), byref(cm), f)
141
142    def set_fade(this, cm, f):
143        return this._set_fade(byref(this), byref(cm), f)
144
145    def to_dB(this, channel = None):
146        if channel is None:
147            return this._to_dB(this.max())
148
149        return this._to_dB(this.values[channel])
150
151cm = ChannelMap()
152
153if len(sys.argv) > 1:
154    cm.parse(sys.argv[1])
155else:
156    cm.parse("surround-51")
157
158v = CVolume()
159v.channels = cm.channels
160
161for i in range(cm.channels):
162    v.values[i] = 65536
163
164title = cm.to_pretty_name()
165if title is None:
166    title = cm.snprint()
167
168window = gtk.Window(gtk.WINDOW_TOPLEVEL)
169window.set_title(unicode(title))
170window.set_border_width(12)
171
172vbox = gtk.VBox(spacing=6)
173
174channel_labels = {}
175channel_scales = {}
176channel_dB_labels = {}
177
178def update_volume(update_channels = True, update_fade = True, update_balance = True, update_scale = True):
179    if update_channels:
180        for i in range(cm.channels):
181            channel_scales[i].set_value(v.values[i])
182
183    if update_scale:
184        value_scale.set_value(v.max())
185
186    if update_balance:
187        balance_scale.set_value(v.get_balance(cm))
188
189    if update_fade:
190        fade_scale.set_value(v.get_fade(cm))
191
192    for i in range(cm.channels):
193        channel_dB_labels[i].set_label("%0.2f dB" % v.to_dB(i))
194
195    value_dB_label.set_label("%0.2f dB" % v.to_dB())
196
197def fade_value_changed(fs):
198    v.set_fade(cm, fade_scale.get_value())
199    update_volume(update_fade = False)
200
201def balance_value_changed(fs):
202    v.set_balance(cm, balance_scale.get_value())
203    update_volume(update_balance = False)
204
205def value_value_changed(fs):
206    v.scale(int(value_scale.get_value()))
207    update_volume(update_scale = False)
208
209def channel_value_changed(fs, i):
210    v.values[i] = int(channel_scales[i].get_value())
211    update_volume(update_channels = False)
212
213for i in range(cm.channels):
214    channel_labels[i] = gtk.Label(cm.position_to_pretty_string(cm.map[i]))
215    channel_labels[i].set_alignment(0, 1)
216    vbox.pack_start(channel_labels[i], expand=False, fill=True)
217
218    channel_scales[i] = gtk.HScale()
219    channel_scales[i].set_range(0, 65536*3/2)
220    channel_scales[i].set_digits(0)
221    channel_scales[i].set_value_pos(gtk.POS_RIGHT)
222    vbox.pack_start(channel_scales[i], expand=False, fill=True)
223
224    channel_dB_labels[i] = gtk.Label("-xxx dB")
225    channel_dB_labels[i].set_alignment(1, 1)
226    vbox.pack_start(channel_dB_labels[i], expand=False, fill=True)
227
228value_label = gtk.Label("Value")
229value_label.set_alignment(0, .5)
230vbox.pack_start(value_label, expand=False, fill=True)
231value_scale = gtk.HScale()
232value_scale.set_range(0, 65536*3/2)
233value_scale.set_value_pos(gtk.POS_RIGHT)
234value_scale.set_digits(0)
235vbox.pack_start(value_scale, expand=False, fill=True)
236value_dB_label = gtk.Label("-xxx dB")
237value_dB_label.set_alignment(1, 1)
238vbox.pack_start(value_dB_label, expand=False, fill=True)
239
240balance_label = gtk.Label("Balance")
241balance_label.set_alignment(0, .5)
242vbox.pack_start(balance_label, expand=False, fill=True)
243balance_scale = gtk.HScale()
244balance_scale.set_range(-1.0, +1.0)
245balance_scale.set_value_pos(gtk.POS_RIGHT)
246balance_scale.set_digits(2)
247vbox.pack_start(balance_scale, expand=False, fill=True)
248
249fade_label = gtk.Label("Fade")
250fade_label.set_alignment(0, .5)
251vbox.pack_start(fade_label, expand=False, fill=True)
252fade_scale = gtk.HScale()
253fade_scale.set_range(-1.0, +1.0)
254fade_scale.set_value_pos(gtk.POS_RIGHT)
255fade_scale.set_digits(2)
256vbox.pack_start(fade_scale, expand=False, fill=True)
257
258window.add(vbox)
259window.set_default_size(600, 50)
260
261update_volume()
262
263for i in range(cm.channels):
264    channel_scales[i].connect("value_changed", channel_value_changed, i)
265fade_scale.connect("value_changed", fade_value_changed)
266balance_scale.connect("value_changed", balance_value_changed)
267value_scale.connect("value_changed", value_value_changed)
268
269vbox.show_all()
270
271if not cm.can_balance():
272    balance_label.hide()
273    balance_scale.hide()
274
275if not cm.can_fade():
276    fade_label.hide()
277    fade_scale.hide()
278
279
280window.show()
281
282gtk.main()
283