source: python/vendor/Python-2.6.5/Tools/audiopy/audiopy

Last change on this file was 2, checked in by Yuri Dario, 15 years ago

Initial import for vendor code.

  • Property svn:eol-style set to native
File size: 16.3 KB
Line 
1#! /usr/bin/env python
2
3"""audiopy -- a program to control the Solaris audio device.
4
5Contact: Barry Warsaw
6Email: bwarsaw@python.org
7Version: %(__version__)s
8
9When no arguments are given, this pops up a graphical window which lets you
10choose the audio input and output devices, and set the output volume.
11
12This program can be driven via the command line, and when done so, no window
13pops up. Most options have the general form:
14
15 --device[={0,1}]
16 -d[={0,1}]
17 Set the I/O device. With no value, it toggles the specified device.
18 With a value, 0 turns the device off and 1 turns the device on.
19
20The list of devices and their short options are:
21
22 (input)
23 microphone -- m
24 linein -- i
25 cd -- c
26
27 (output)
28 headphones -- p
29 speaker -- s
30 lineout -- o
31
32Other options are:
33
34 --gain volume
35 -g volume
36 Sets the output gain to the specified volume, which must be an integer
37 in the range [%(MIN_GAIN)s..%(MAX_GAIN)s]
38
39 --version
40 -v
41 Print the version number and exit.
42
43 --help
44 -h
45 Print this message and exit.
46"""
47
48import sys
49import os
50import errno
51import sunaudiodev
52from SUNAUDIODEV import *
53
54# Milliseconds between interrupt checks
55KEEPALIVE_TIMER = 500
56
57__version__ = '1.1'
58
59
60
61
62class MainWindow:
63 def __init__(self, device):
64 from Tkinter import *
65 self.__helpwin = None
66 self.__devctl = device
67 info = device.getinfo()
68 #
69 self.__tkroot = tkroot = Tk(className='Audiopy')
70 tkroot.withdraw()
71 # create the menubar
72 menubar = Menu(tkroot)
73 filemenu = Menu(menubar, tearoff=0)
74 filemenu.add_command(label='Quit',
75 command=self.__quit,
76 accelerator='Alt-Q',
77 underline=0)
78 helpmenu = Menu(menubar, name='help', tearoff=0)
79 helpmenu.add_command(label='About Audiopy...',
80 command=self.__popup_about,
81 underline=0)
82 helpmenu.add_command(label='Help...',
83 command=self.__popup_using,
84 underline=0)
85 menubar.add_cascade(label='File',
86 menu=filemenu,
87 underline=0)
88 menubar.add_cascade(label='Help',
89 menu=helpmenu,
90 underline=0)
91 # now create the top level window
92 root = self.__root = Toplevel(tkroot, class_='Audiopy', menu=menubar)
93 root.protocol('WM_DELETE_WINDOW', self.__quit)
94 root.title('audiopy ' + __version__)
95 root.iconname('audiopy ' + __version__)
96 root.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
97 #
98 buttons = []
99 #
100 # where does input come from?
101 frame = Frame(root, bd=1, relief=RAISED)
102 frame.grid(row=1, column=0, sticky='NSEW')
103 label = Label(frame, text='Input From:')
104 label.grid(row=0, column=0, sticky=E)
105 self.__inputvar = IntVar()
106 ##
107 btn = Radiobutton(frame,
108 text='None',
109 variable=self.__inputvar,
110 value=0,
111 command=self.__pushtodev,
112 underline=0)
113 btn.grid(row=0, column=1, sticky=W)
114 root.bind('<Alt-n>', self.__none)
115 root.bind('<Alt-N>', self.__none)
116 if not info.i_avail_ports & MICROPHONE:
117 btn.configure(state=DISABLED)
118 buttons.append(btn)
119 ##
120 btn = Radiobutton(frame,
121 text='Microphone',
122 variable=self.__inputvar,
123 value=MICROPHONE,
124 command=self.__pushtodev,
125 underline=0)
126 btn.grid(row=1, column=1, sticky=W)
127 root.bind('<Alt-m>', self.__mic)
128 root.bind('<Alt-M>', self.__mic)
129 if not info.i_avail_ports & MICROPHONE:
130 btn.configure(state=DISABLED)
131 buttons.append(btn)
132 ##
133 btn = Radiobutton(frame,
134 text='Line In',
135 variable=self.__inputvar,
136 value=LINE_IN,
137 command=self.__pushtodev,
138 underline=5)
139 btn.grid(row=2, column=1, sticky=W)
140 root.bind('<Alt-i>', self.__linein)
141 root.bind('<Alt-I>', self.__linein)
142 if not info.i_avail_ports & LINE_IN:
143 btn.configure(state=DISABLED)
144 buttons.append(btn)
145 ## if SUNAUDIODEV was built on an older version of Solaris, the CD
146 ## input device won't exist
147 try:
148 btn = Radiobutton(frame,
149 text='CD',
150 variable=self.__inputvar,
151 value=CD,
152 command=self.__pushtodev,
153 underline=0)
154 btn.grid(row=3, column=1, sticky=W)
155 root.bind('<Alt-c>', self.__cd)
156 root.bind('<Alt-C>', self.__cd)
157 if not info.i_avail_ports & CD:
158 btn.configure(state=DISABLED)
159 buttons.append(btn)
160 except NameError:
161 pass
162 #
163 # where does output go to?
164 frame = Frame(root, bd=1, relief=RAISED)
165 frame.grid(row=2, column=0, sticky='NSEW')
166 label = Label(frame, text='Output To:')
167 label.grid(row=0, column=0, sticky=E)
168 self.__spkvar = IntVar()
169 btn = Checkbutton(frame,
170 text='Speaker',
171 variable=self.__spkvar,
172 onvalue=SPEAKER,
173 command=self.__pushtodev,
174 underline=0)
175 btn.grid(row=0, column=1, sticky=W)
176 root.bind('<Alt-s>', self.__speaker)
177 root.bind('<Alt-S>', self.__speaker)
178 if not info.o_avail_ports & SPEAKER:
179 btn.configure(state=DISABLED)
180 buttons.append(btn)
181 ##
182 self.__headvar = IntVar()
183 btn = Checkbutton(frame,
184 text='Headphones',
185 variable=self.__headvar,
186 onvalue=HEADPHONE,
187 command=self.__pushtodev,
188 underline=4)
189 btn.grid(row=1, column=1, sticky=W)
190 root.bind('<Alt-p>', self.__headphones)
191 root.bind('<Alt-P>', self.__headphones)
192 if not info.o_avail_ports & HEADPHONE:
193 btn.configure(state=DISABLED)
194 buttons.append(btn)
195 ##
196 self.__linevar = IntVar()
197 btn = Checkbutton(frame,
198 variable=self.__linevar,
199 onvalue=LINE_OUT,
200 text='Line Out',
201 command=self.__pushtodev,
202 underline=0)
203 btn.grid(row=2, column=1, sticky=W)
204 root.bind('<Alt-l>', self.__lineout)
205 root.bind('<Alt-L>', self.__lineout)
206 if not info.o_avail_ports & LINE_OUT:
207 btn.configure(state=DISABLED)
208 buttons.append(btn)
209 #
210 # Fix up widths
211 widest = 0
212 for b in buttons:
213 width = b['width']
214 if width > widest:
215 widest = width
216 for b in buttons:
217 b.configure(width=widest)
218 # root bindings
219 root.bind('<Alt-q>', self.__quit)
220 root.bind('<Alt-Q>', self.__quit)
221 #
222 # Volume
223 frame = Frame(root, bd=1, relief=RAISED)
224 frame.grid(row=3, column=0, sticky='NSEW')
225 label = Label(frame, text='Output Volume:')
226 label.grid(row=0, column=0, sticky=W)
227 self.__scalevar = IntVar()
228 self.__scale = Scale(frame,
229 orient=HORIZONTAL,
230 from_=MIN_GAIN,
231 to=MAX_GAIN,
232 length=200,
233 variable=self.__scalevar,
234 command=self.__volume)
235 self.__scale.grid(row=1, column=0, sticky=EW)
236 #
237 # do we need to poll for changes?
238 self.__needtopoll = 1
239 try:
240 fd = self.__devctl.fileno()
241 self.__needtopoll = 0
242 except AttributeError:
243 pass
244 else:
245 import fcntl
246 import signal
247 import STROPTS
248 # set up the signal handler
249 signal.signal(signal.SIGPOLL, self.__update)
250 fcntl.ioctl(fd, STROPTS.I_SETSIG, STROPTS.S_MSG)
251 self.__update()
252
253 def __quit(self, event=None):
254 self.__devctl.close()
255 self.__root.quit()
256
257 def __popup_about(self, event=None):
258 import tkMessageBox
259 tkMessageBox.showinfo('About Audiopy ' + __version__,
260 '''\
261Audiopy %s
262Control the Solaris audio device
263
264For information
265Contact: Barry A. Warsaw
266Email: bwarsaw@python.org''' % __version__)
267
268 def __popup_using(self, event=None):
269 if not self.__helpwin:
270 self.__helpwin = Helpwin(self.__tkroot, self.__quit)
271 self.__helpwin.deiconify()
272
273
274 def __keepalive(self):
275 # Exercise the Python interpreter regularly so keyboard interrupts get
276 # through.
277 self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
278 if self.__needtopoll:
279 self.__update()
280
281 def __update(self, num=None, frame=None):
282 # It's possible (although I have never seen it) to get an interrupted
283 # system call during the getinfo() call. If so, and we're polling,
284 # don't sweat it because we'll come around again later. Otherwise,
285 # we'll give it a couple of tries and then give up until next time.
286 tries = 0
287 while 1:
288 try:
289 info = self.__devctl.getinfo()
290 break
291 except sunaudiodev.error:
292 if self.__needtopoll or tries > 3:
293 return
294 tries = tries + 1
295 # input
296 self.__inputvar.set(info.i_port)
297 # output
298 self.__spkvar.set(info.o_port & SPEAKER)
299 self.__headvar.set(info.o_port & HEADPHONE)
300 self.__linevar.set(info.o_port & LINE_OUT)
301 # volume
302 self.__scalevar.set(info.o_gain)
303
304 def __pushtodev(self, event=None):
305 info = self.__devctl.getinfo()
306 info.o_port = self.__spkvar.get() + \
307 self.__headvar.get() + \
308 self.__linevar.get()
309 info.i_port = self.__inputvar.get()
310 info.o_gain = self.__scalevar.get()
311 try:
312 self.__devctl.setinfo(info)
313 except sunaudiodev.error, msg:
314 # TBD: what to do? it's probably temporary.
315 pass
316
317 def __getset(self, var, onvalue):
318 if var.get() == onvalue:
319 var.set(0)
320 else:
321 var.set(onvalue)
322 self.__pushtodev()
323
324 def __none(self, event=None):
325 self.__inputvar.set(0)
326 self.__pushtodev()
327
328 def __mic(self, event=None):
329 self.__getset(self.__inputvar, MICROPHONE)
330
331 def __linein(self, event=None):
332 self.__getset(self.__inputvar, LINE_IN)
333
334 def __cd(self, event=None):
335 self.__getset(self.__inputvar, CD)
336
337 def __speaker(self, event=None):
338 self.__getset(self.__spkvar, SPEAKER)
339
340 def __headphones(self, event=None):
341 self.__getset(self.__headvar, HEADPHONE)
342
343 def __lineout(self, event=None):
344 self.__getset(self.__linevar, LINE_OUT)
345
346 def __volume(self, event=None):
347 self.__pushtodev()
348
349 def start(self):
350 self.__keepalive()
351 self.__tkroot.mainloop()
352
353
354
355
356class Helpwin:
357 def __init__(self, master, quitfunc):
358 from Tkinter import *
359 self.__root = root = Toplevel(master, class_='Audiopy')
360 root.protocol('WM_DELETE_WINDOW', self.__withdraw)
361 root.title('Audiopy Help Window')
362 root.iconname('Audiopy Help Window')
363 root.bind('<Alt-q>', quitfunc)
364 root.bind('<Alt-Q>', quitfunc)
365 root.bind('<Alt-w>', self.__withdraw)
366 root.bind('<Alt-W>', self.__withdraw)
367
368 # more elaborate help is available in the README file
369 readmefile = os.path.join(sys.path[0], 'README')
370 try:
371 fp = None
372 try:
373 fp = open(readmefile)
374 contents = fp.read()
375 # wax the last page, it contains Emacs cruft
376 i = contents.rfind('\f')
377 if i > 0:
378 contents = contents[:i].rstrip()
379 finally:
380 if fp:
381 fp.close()
382 except IOError:
383 sys.stderr.write("Couldn't open audiopy's README, "
384 'using docstring instead.\n')
385 contents = __doc__ % globals()
386
387 self.__text = text = Text(root, relief=SUNKEN,
388 width=80, height=24)
389 text.insert(0.0, contents)
390 scrollbar = Scrollbar(root)
391 scrollbar.pack(fill=Y, side=RIGHT)
392 text.pack(fill=BOTH, expand=YES)
393 text.configure(yscrollcommand=(scrollbar, 'set'))
394 scrollbar.configure(command=(text, 'yview'))
395
396 def __withdraw(self, event=None):
397 self.__root.withdraw()
398
399 def deiconify(self):
400 self.__root.deiconify()
401
402
403
404
405
406def usage(code, msg=''):
407 print __doc__ % globals()
408 if msg:
409 print msg
410 sys.exit(code)
411
412
413def main():
414 #
415 # Open up the audio control device and query for the current output
416 # device
417 device = sunaudiodev.open('control')
418
419 if len(sys.argv) == 1:
420 # GUI
421 w = MainWindow(device)
422 try:
423 w.start()
424 except KeyboardInterrupt:
425 pass
426 return
427
428 # spec: LONG OPT, SHORT OPT, 0=input,1=output, MASK
429 options = [('--microphone', '-m', 0, MICROPHONE),
430 ('--linein', '-i', 0, LINE_IN),
431 ('--headphones', '-p', 1, HEADPHONE),
432 ('--speaker', '-s', 1, SPEAKER),
433 ('--lineout', '-o', 1, LINE_OUT),
434 ]
435 # See the comment above about `CD'
436 try:
437 options.append(('--cd', '-c', 0, CD))
438 except NameError:
439 pass
440
441 info = device.getinfo()
442 # first get the existing values
443 i = 0
444 while i < len(sys.argv)-1:
445 i = i + 1
446 arg = sys.argv[i]
447 if arg in ('-h', '--help'):
448 usage(0)
449 # does not return
450 elif arg in ('-g', '--gain'):
451 gainspec = '<missing>'
452 try:
453 gainspec = sys.argv[i+1]
454 gain = int(gainspec)
455 except (ValueError, IndexError):
456 usage(1, 'Bad gain specification: ' + gainspec)
457 info.o_gain = gain
458 i = i + 1
459 continue
460 elif arg in ('-v', '--version'):
461 print '''\
462audiopy -- a program to control the Solaris audio device.
463Contact: Barry Warsaw
464Email: bwarsaw@python.org
465Version: %s''' % __version__
466 sys.exit(0)
467 for long, short, io, mask in options:
468 if arg in (long, short):
469 # toggle the option
470 if io == 0:
471 info.i_port = info.i_port ^ mask
472 else:
473 info.o_port = info.o_port ^ mask
474 break
475 val = None
476 try:
477 if arg[:len(long)+1] == long+'=':
478 val = int(arg[len(long)+1:])
479 elif arg[:len(short)+1] == short+'=':
480 val = int(arg[len(short)+1:])
481 except ValueError:
482 usage(1, msg='Invalid option: ' + arg)
483 # does not return
484 if val == 0:
485 if io == 0:
486 info.i_port = info.i_port & ~mask
487 else:
488 info.o_port = info.o_port & ~mask
489 break
490 elif val == 1:
491 if io == 0:
492 info.i_port = info.i_port | mask
493 else:
494 info.o_port = info.o_port | mask
495 break
496 # else keep trying next option
497 else:
498 usage(1, msg='Invalid option: ' + arg)
499 # now set the values
500 try:
501 device.setinfo(info)
502 except sunaudiodev.error, (code, msg):
503 if code <> errno.EINVAL:
504 raise
505 device.close()
506
507
508
509
510if __name__ == '__main__':
511 main()
Note: See TracBrowser for help on using the repository browser.