]> code.delx.au - pulseaudio/blob - src/tests/volume-ui.py
allow passing of channel map on command line and hide unused sliders
[pulseaudio] / src / tests / volume-ui.py
1 #!/usr/bin/python
2
3 import pygtk, gtk, sys
4 from ctypes import *
5
6 try:
7 libpulse = cdll.LoadLibrary("../.libs/libpulse.so")
8 except OSError:
9 try:
10 libpulse = cdll.LoadLibrary(".libs/libpulse.so")
11 except OSError:
12 libpulse = cdll.LoadLibrary("libpulse.so")
13
14 class 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
82 class 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 def snprint(this):
115 s = create_string_buffer(320)
116 r = this._snprint(s, len(s), byref(this))
117
118 if r is None:
119 return None
120 else:
121 return s.raw
122
123 def max(this):
124 return this._max(byref(this))
125
126 def scale(this, v):
127 return this._scale(byref(this), v)
128
129 def get_balance(this, cm):
130 return this._get_balance(byref(this), byref(cm))
131
132 def get_fade(this, cm):
133 return this._get_fade(byref(this), byref(cm))
134
135 def set_balance(this, cm, f):
136 return this._set_balance(byref(this), byref(cm), f)
137
138 def set_fade(this, cm, f):
139 return this._set_fade(byref(this), byref(cm), f)
140
141 cm = ChannelMap()
142
143 if len(sys.argv) > 1:
144 cm.parse(sys.argv[1])
145 else:
146 cm.parse("surround-51")
147
148 v = CVolume()
149 v.channels = cm.channels
150
151 for i in range(cm.channels):
152 v.values[i] = 65536/2
153
154 title = cm.to_pretty_name()
155 if title is None:
156 title = cm.snprint()
157
158 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
159 window.set_title(unicode(title))
160 window.set_border_width(12)
161
162 vbox = gtk.VBox(spacing=6)
163
164 channel_labels = {}
165 channel_scales = {}
166
167 def update_volume(update_channels = True, update_fade = True, update_balance = True, update_scale = True):
168 if update_channels:
169 for i in range(cm.channels):
170 channel_scales[i].set_value(v.values[i])
171
172 if update_scale:
173 value_scale.set_value(v.max())
174
175 if update_balance:
176 balance_scale.set_value(v.get_balance(cm))
177
178 if update_fade:
179 fade_scale.set_value(v.get_fade(cm))
180
181 def fade_value_changed(fs):
182 v.set_fade(cm, fade_scale.get_value())
183 update_volume(update_fade = False)
184
185 def balance_value_changed(fs):
186 v.set_balance(cm, balance_scale.get_value())
187 update_volume(update_balance = False)
188
189 def value_value_changed(fs):
190 v.scale(int(value_scale.get_value()))
191 update_volume(update_scale = False)
192
193 def channel_value_changed(fs, i):
194 v.values[i] = int(channel_scales[i].get_value())
195 update_volume(update_channels = False)
196
197 for i in range(cm.channels):
198 channel_labels[i] = gtk.Label(cm.position_to_pretty_string(cm.map[i]))
199 channel_labels[i].set_alignment(0, 1)
200 vbox.pack_start(channel_labels[i], expand=False, fill=True)
201
202 channel_scales[i] = gtk.HScale()
203 channel_scales[i].set_range(0, 65536)
204 channel_scales[i].set_digits(0)
205 channel_scales[i].set_value_pos(gtk.POS_RIGHT)
206 vbox.pack_start(channel_scales[i], expand=False, fill=True)
207
208 value_label = gtk.Label("Value")
209 value_label.set_alignment(0, .5)
210 vbox.pack_start(value_label, expand=False, fill=True)
211 value_scale = gtk.HScale()
212 value_scale.set_range(0, 65536)
213 value_scale.set_value_pos(gtk.POS_RIGHT)
214 value_scale.set_digits(0)
215 vbox.pack_start(value_scale, expand=False, fill=True)
216
217 balance_label = gtk.Label("Balance")
218 balance_label.set_alignment(0, .5)
219 vbox.pack_start(balance_label, expand=False, fill=True)
220 balance_scale = gtk.HScale()
221 balance_scale.set_range(-1.0, +1.0)
222 balance_scale.set_value_pos(gtk.POS_RIGHT)
223 balance_scale.set_digits(2)
224 vbox.pack_start(balance_scale, expand=False, fill=True)
225
226 fade_label = gtk.Label("Fade")
227 fade_label.set_alignment(0, .5)
228 vbox.pack_start(fade_label, expand=False, fill=True)
229 fade_scale = gtk.HScale()
230 fade_scale.set_range(-1.0, +1.0)
231 fade_scale.set_value_pos(gtk.POS_RIGHT)
232 fade_scale.set_digits(2)
233 vbox.pack_start(fade_scale, expand=False, fill=True)
234
235 window.add(vbox)
236 window.set_default_size(600, 50)
237
238 update_volume()
239
240 for i in range(cm.channels):
241 channel_scales[i].connect("value_changed", channel_value_changed, i)
242 fade_scale.connect("value_changed", fade_value_changed)
243 balance_scale.connect("value_changed", balance_value_changed)
244 value_scale.connect("value_changed", value_value_changed)
245
246 vbox.show_all()
247
248 if not cm.can_balance():
249 balance_label.hide()
250 balance_scale.hide()
251
252 if not cm.can_fade():
253 fade_label.hide()
254 fade_scale.hide()
255
256
257 window.show()
258
259 gtk.main()