3 """audiopy -- a program to control the Solaris audio device.
6 Email: bwarsaw@python.org
7 Version: %(__version__)s
9 When no arguments are given, this pops up a graphical window which lets you
10 choose the audio input and output devices.
12 This program can be driven via the command line, and when done so, no window
13 pops up. Options have the general form:
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.
20 The list of devices and their short options are:
36 Print the version number and exit.
40 Print this message and exit.
47 from SUNAUDIODEV
import *
49 # Milliseconds between interrupt checks
57 def __init__(self
, device
):
60 self
.__devctl
= device
61 info
= device
.getinfo()
63 self
.__tkroot
= tkroot
= Tk(className
='Audiopy')
66 menubar
= Menu(tkroot
)
67 filemenu
= Menu(menubar
, tearoff
=0)
68 filemenu
.add_command(label
='Quit',
72 helpmenu
= Menu(menubar
, name
='help', tearoff
=0)
73 helpmenu
.add_command(label
='About Audiopy...',
74 command
=self
.__popup
_about
,
76 helpmenu
.add_command(label
='Help...',
77 command
=self
.__popup
_using
,
79 menubar
.add_cascade(label
='File',
82 menubar
.add_cascade(label
='Help',
85 # now create the top level window
86 root
= self
.__root
= Toplevel(tkroot
, class_
='Audiopy', menu
=menubar
)
87 root
.protocol('WM_DELETE_WINDOW', self
.__quit
)
88 root
.title('audiopy ' + __version__
)
89 root
.iconname('audiopy ' + __version__
)
90 root
.tk
.createtimerhandler(KEEPALIVE_TIMER
, self
.__keepalive
)
94 # where does input come from?
95 frame
= Frame(root
, bd
=1, relief
=RAISED
)
96 frame
.grid(row
=1, column
=0, sticky
='NSEW')
97 label
= Label(frame
, text
='Input From:')
98 label
.grid(row
=0, column
=0, sticky
=E
)
99 self
.__inputvar
= IntVar()
101 btn
= Radiobutton(frame
,
103 variable
=self
.__inputvar
,
105 command
=self
.__pushtodev
,
107 btn
.grid(row
=0, column
=1, sticky
=W
)
108 root
.bind('<Alt-n>', self
.__none
)
109 root
.bind('<Alt-N>', self
.__none
)
110 if not info
.i_avail_ports
& MICROPHONE
:
111 btn
.configure(state
=DISABLED
)
114 btn
= Radiobutton(frame
,
116 variable
=self
.__inputvar
,
118 command
=self
.__pushtodev
,
120 btn
.grid(row
=1, column
=1, sticky
=W
)
121 root
.bind('<Alt-m>', self
.__mic
)
122 root
.bind('<Alt-M>', self
.__mic
)
123 if not info
.i_avail_ports
& MICROPHONE
:
124 btn
.configure(state
=DISABLED
)
127 btn
= Radiobutton(frame
,
129 variable
=self
.__inputvar
,
131 command
=self
.__pushtodev
,
133 btn
.grid(row
=2, column
=1, sticky
=W
)
134 root
.bind('<Alt-i>', self
.__linein
)
135 root
.bind('<Alt-I>', self
.__linein
)
136 if not info
.i_avail_ports
& LINE_IN
:
137 btn
.configure(state
=DISABLED
)
139 ## if SUNAUDIODEV was built on an older version of Solaris, the CD
140 ## input device won't exist
142 btn
= Radiobutton(frame
,
144 variable
=self
.__inputvar
,
146 command
=self
.__pushtodev
,
148 btn
.grid(row
=3, column
=1, sticky
=W
)
149 root
.bind('<Alt-c>', self
.__cd
)
150 root
.bind('<Alt-C>', self
.__cd
)
151 if not info
.i_avail_ports
& CD
:
152 btn
.configure(state
=DISABLED
)
157 # where does output go to?
158 frame
= Frame(root
, bd
=1, relief
=RAISED
)
159 frame
.grid(row
=2, column
=0, sticky
='NSEW')
160 label
= Label(frame
, text
='Output To:')
161 label
.grid(row
=0, column
=0, sticky
=E
)
162 self
.__spkvar
= IntVar()
163 btn
= Checkbutton(frame
,
165 variable
=self
.__spkvar
,
167 command
=self
.__pushtodev
,
169 btn
.grid(row
=0, column
=1, sticky
=W
)
170 root
.bind('<Alt-s>', self
.__speaker
)
171 root
.bind('<Alt-S>', self
.__speaker
)
172 if not info
.o_avail_ports
& SPEAKER
:
173 btn
.configure(state
=DISABLED
)
176 self
.__headvar
= IntVar()
177 btn
= Checkbutton(frame
,
179 variable
=self
.__headvar
,
181 command
=self
.__pushtodev
,
183 btn
.grid(row
=1, column
=1, sticky
=W
)
184 root
.bind('<Alt-p>', self
.__headphones
)
185 root
.bind('<Alt-P>', self
.__headphones
)
186 if not info
.o_avail_ports
& HEADPHONE
:
187 btn
.configure(state
=DISABLED
)
190 self
.__linevar
= IntVar()
191 btn
= Checkbutton(frame
,
192 variable
=self
.__linevar
,
195 command
=self
.__pushtodev
,
197 btn
.grid(row
=2, column
=1, sticky
=W
)
198 root
.bind('<Alt-l>', self
.__lineout
)
199 root
.bind('<Alt-L>', self
.__lineout
)
200 if not info
.o_avail_ports
& LINE_OUT
:
201 btn
.configure(state
=DISABLED
)
211 b
.configure(width
=widest
)
213 root
.bind('<Alt-q>', self
.__quit
)
214 root
.bind('<Alt-Q>', self
.__quit
)
216 # do we need to poll for changes?
217 self
.__needtopoll
= 1
219 fd
= self
.__devctl
.fileno()
220 self
.__needtopoll
= 0
221 except AttributeError:
227 # set up the signal handler
228 signal
.signal(signal
.SIGPOLL
, self
.__update
)
229 fcntl
.ioctl(fd
, STROPTS
.I_SETSIG
, STROPTS
.S_MSG
)
232 def __quit(self
, event
=None):
233 self
.__devctl
.close()
236 def __popup_about(self
, event
=None):
238 tkMessageBox
.showinfo('About Audiopy ' + __version__
,
241 Control the Solaris audio device
244 Contact: Barry A. Warsaw
245 Email: bwarsaw@python.org''' % __version__
)
247 def __popup_using(self
, event
=None):
248 if not self
.__helpwin
:
249 self
.__helpwin
= Helpwin(self
.__tkroot
, self
.__quit
)
250 self
.__helpwin
.deiconify()
253 def __keepalive(self
):
254 # Exercise the Python interpreter regularly so keyboard interrupts get
256 self
.__tkroot
.tk
.createtimerhandler(KEEPALIVE_TIMER
, self
.__keepalive
)
257 if self
.__needtopoll
:
260 def __update(self
, num
=None, frame
=None):
261 # We have to poll because the device could have changed state and the
262 # underlying module does not support the SIGPOLL notification
264 info
= self
.__devctl
.getinfo()
266 self
.__inputvar
.set(info
.i_port
)
268 self
.__spkvar
.set(info
.o_port
& SPEAKER
)
269 self
.__headvar
.set(info
.o_port
& HEADPHONE
)
270 self
.__linevar
.set(info
.o_port
& LINE_OUT
)
272 def __pushtodev(self
, event
=None):
273 info
= self
.__devctl
.getinfo()
274 info
.o_port
= self
.__spkvar
.get() + \
275 self
.__headvar
.get() + \
277 info
.i_port
= self
.__inputvar
.get()
278 self
.__devctl
.setinfo(info
)
280 def __getset(self
, var
, onvalue
):
281 if var
.get() == onvalue
:
287 def __none(self
, event
=None):
288 self
.__inputvar
.set(0)
291 def __mic(self
, event
=None):
292 self
.__getset
(self
.__inputvar
, MICROPHONE
)
294 def __linein(self
, event
=None):
295 self
.__getset
(self
.__inputvar
, LINE_IN
)
297 def __cd(self
, event
=None):
298 self
.__getset
(self
.__inputvar
, CD
)
300 def __speaker(self
, event
=None):
301 self
.__getset
(self
.__spkvar
, SPEAKER
)
303 def __headphones(self
, event
=None):
304 self
.__getset
(self
.__headvar
, HEADPHONE
)
306 def __lineout(self
, event
=None):
307 self
.__getset
(self
.__linevar
, LINE_OUT
)
311 self
.__tkroot
.mainloop()
316 def __init__(self
, master
, quitfunc
):
317 from Tkinter
import *
318 self
.__root
= root
= Toplevel(master
, class_
='Audiopy')
319 root
.protocol('WM_DELETE_WINDOW', self
.__withdraw
)
320 root
.title('Audiopy Help Window')
321 root
.iconname('Audiopy Help Window')
322 root
.bind('<Alt-q>', quitfunc
)
323 root
.bind('<Alt-Q>', quitfunc
)
324 root
.bind('<Alt-w>', self
.__withdraw
)
325 root
.bind('<Alt-W>', self
.__withdraw
)
327 # more elaborate help is available in the README file
328 readmefile
= os
.path
.join(sys
.path
[0], 'README')
332 fp
= open(readmefile
)
334 # wax the last page, it contains Emacs cruft
335 i
= string
.rfind(contents
, '\f')
337 contents
= string
.rstrip(contents
[:i
])
342 sys
.stderr
.write("Couldn't open audiopy's README, "
343 'using docstring instead.\n')
344 contents
= __doc__
% globals()
346 self
.__text
= text
= Text(root
, relief
=SUNKEN
,
348 text
.insert(0.0, contents
)
349 scrollbar
= Scrollbar(root
)
350 scrollbar
.pack(fill
=Y
, side
=RIGHT
)
351 text
.pack(fill
=BOTH
, expand
=YES
)
352 text
.configure(yscrollcommand
=(scrollbar
, 'set'))
353 scrollbar
.configure(command
=(text
, 'yview'))
355 def __withdraw(self
, event
=None):
356 self
.__root
.withdraw()
359 self
.__root
.deiconify()
364 def usage(msg
='', code
=1):
365 print __doc__
% globals()
373 # Open up the audio control device and query for the current output
375 device
= sunaudiodev
.open('control')
377 if len(sys
.argv
) == 1:
379 w
= MainWindow(device
)
382 except KeyboardInterrupt:
386 # spec: LONG OPT, SHORT OPT, 0=input,1=output, MASK
387 options
= [('--microphone', '-m', 0, MICROPHONE
),
388 ('--linein', '-i', 0, LINE_IN
),
389 ('--headphones', '-p', 1, HEADPHONE
),
390 ('--speaker', '-s', 1, SPEAKER
),
391 ('--lineout', '-o', 1, LINE_OUT
),
393 # See the comment above about `CD'
395 options
.append(('--cd', '-c', 0, CD
))
399 info
= device
.getinfo()
400 # first get the existing values
401 for arg
in sys
.argv
[1:]:
402 if arg
in ('-h', '--help'):
405 elif arg
in ('-v', '--version'):
407 audiopy -- a program to control the Solaris audio device.
408 Contact: Barry Warsaw
409 Email: bwarsaw@python.org
410 Version: %s''' % __version__
412 for long, short
, io
, mask
in options
:
413 if arg
in (long, short
):
416 info
.i_port
= info
.i_port ^ mask
418 info
.o_port
= info
.o_port ^ mask
422 if arg
[:len(long)+1] == long+'=':
423 val
= int(arg
[len(long)+1:])
424 elif arg
[:len(short
)+1] == short
+'=':
425 val
= int(arg
[len(short
)+1:])
427 usage(msg
='Invalid option: ' + arg
)
431 info
.i_port
= info
.i_port
& ~mask
433 info
.o_port
= info
.o_port
& ~mask
437 info
.i_port
= info
.i_port | mask
439 info
.o_port
= info
.o_port | mask
441 # else keep trying next option
443 usage(msg
='Invalid option: ' + arg
)
450 if __name__
== '__main__':