summaryrefslogtreecommitdiff
path: root/sys/src/cmd/python/Tools/audiopy
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
committercinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
commit458120dd40db6b4df55a4e96b650e16798ef06a0 (patch)
tree8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/src/cmd/python/Tools/audiopy
parent3a742c699f6806c1145aea5149bf15de15a0afd7 (diff)
add hg and python
Diffstat (limited to 'sys/src/cmd/python/Tools/audiopy')
-rw-r--r--sys/src/cmd/python/Tools/audiopy/README112
-rwxr-xr-xsys/src/cmd/python/Tools/audiopy/audiopy507
2 files changed, 619 insertions, 0 deletions
diff --git a/sys/src/cmd/python/Tools/audiopy/README b/sys/src/cmd/python/Tools/audiopy/README
new file mode 100644
index 000000000..45bf7736f
--- /dev/null
+++ b/sys/src/cmd/python/Tools/audiopy/README
@@ -0,0 +1,112 @@
+audiopy - a program to control the Solaris audio device.
+
+Contact: Barry Warsaw
+Email: bwarsaw@python.org
+Version: 1.1
+
+Introduction
+
+ Audiopy is a program to control the Solaris audio device, allowing
+ you to choose both the input and output devices, and to set the
+ output volume. It can be run either as a standalone command-line
+ script, or as a Tkinter based GUI application.
+
+ Note that your version of Python must have been built with the
+ sunaudiodev module enabled. It is not enabled by default however!
+ You will need to edit your Modules/Setup file, uncomment the
+ sunaudiodev module spec line and rebuild Python.
+
+ Using audiopy, you can select one of three possible input devices:
+ the microphone, the line-in jack, or the CD in. These choices are
+ mutually exclusive; you can only have one active input device at
+ any one time (this is enforced by the underlying device). Some
+ input devices may not be supported on all Solaris machines.
+
+ You can also choose to enable any of the three possible output
+ devices: the headphone jack, the speakers, or the line-out jack.
+ You can enable any combination of these three devices.
+
+ You can also set the output gain (volume) level.
+
+Running as a GUI
+
+ Simply start audiopy with no arguments to start it as a Tkinter
+ based GUI application. It will pop up a window with two sections:
+ the top portion contains three radio buttons indicating your
+ selected input device; the middle portion contains three
+ checkboxes indicating your selected output devices; the bottom
+ portion contains a slider that changes the output gain.
+
+ Note the underlined characters in the button labels. These
+ indicate keyboard accelerators so that pressing Alt+character you
+ can select that device. For example, Alt-s toggles the Speaker
+ device. The Alt accelerators are the same as those you'd use in
+ as the short-form command line switches (see below).
+
+ Alt-q is also an accelerator for selecting Quit from the File
+ menu.
+
+ Unsupported devices will appear dimmed out in the GUI. When run
+ as a GUI, audiopy monitors the audio device and automatically
+ updates its display if the state of the device is changed by some
+ other means. With Python versions before 1.5.2 this is done by
+ occasionally polling the device, but in Python 1.5.2 no polling is
+ necessary (you don't really need to know this, but I thought I'd
+ plug 1.5.2 :-).
+
+Running as a Command Line Program
+
+ You can run audiopy from the command line to select any
+ combination of input or output device, by using the command line
+ options. Actually, any option forces audiopy to run as a command
+ line program and not display its GUI.
+
+ Options have the general form
+
+ --device[={0,1}]
+ -d[-{0,1}]
+
+ meaning there is both a long-form and short-form of the switch,
+ where `device' or `d' is one of the following:
+
+ (input)
+ microphone -- m
+ linein -- i
+ cd -- c
+
+ (output)
+ headphones -- p
+ speaker -- s
+ lineout -- o
+
+ When no value is given, the switch just toggles the specified
+ device. With a value, 0 turns the device off and 1 turns the
+ device on. Any other value is an error.
+
+ For example, to turn the speakers off, turn the headphones on, and
+ toggle the cd input device, run audiopy from the command line like
+ so:
+
+ % ./audiopy -s=0 -p=1 -c
+
+ Audiopy understands these other command line options:
+
+ --gain volume
+ -g volume
+ Sets the output volume to the specified gain level. This must
+ be an integer between MIN_GAIN and MAX_GAIN (usually [0..255],
+ but use the -h option to find the exact values).
+
+ --version
+ -v
+ Print the version number and exit
+
+ --help
+ -h
+ Print a help message and exit
+
+
+
+Local Variables:
+indent-tabs-mode: nil
+End:
diff --git a/sys/src/cmd/python/Tools/audiopy/audiopy b/sys/src/cmd/python/Tools/audiopy/audiopy
new file mode 100755
index 000000000..b817c5cc0
--- /dev/null
+++ b/sys/src/cmd/python/Tools/audiopy/audiopy
@@ -0,0 +1,507 @@
+#! /usr/bin/env python
+
+"""audiopy -- a program to control the Solaris audio device.
+
+Contact: Barry Warsaw
+Email: bwarsaw@python.org
+Version: %(__version__)s
+
+When no arguments are given, this pops up a graphical window which lets you
+choose the audio input and output devices, and set the output volume.
+
+This program can be driven via the command line, and when done so, no window
+pops up. Most options have the general form:
+
+ --device[={0,1}]
+ -d[={0,1}]
+ Set the I/O device. With no value, it toggles the specified device.
+ With a value, 0 turns the device off and 1 turns the device on.
+
+The list of devices and their short options are:
+
+ (input)
+ microphone -- m
+ linein -- i
+ cd -- c
+
+ (output)
+ headphones -- p
+ speaker -- s
+ lineout -- o
+
+Other options are:
+
+ --gain volume
+ -g volume
+ Sets the output gain to the specified volume, which must be an integer
+ in the range [%(MIN_GAIN)s..%(MAX_GAIN)s]
+
+ --version
+ -v
+ Print the version number and exit.
+
+ --help
+ -h
+ Print this message and exit.
+"""
+
+import sys
+import os
+import errno
+import sunaudiodev
+from SUNAUDIODEV import *
+
+# Milliseconds between interrupt checks
+KEEPALIVE_TIMER = 500
+
+__version__ = '1.1'
+
+
+
+class MainWindow:
+ def __init__(self, device):
+ from Tkinter import *
+ self.__helpwin = None
+ self.__devctl = device
+ info = device.getinfo()
+ #
+ self.__tkroot = tkroot = Tk(className='Audiopy')
+ tkroot.withdraw()
+ # create the menubar
+ menubar = Menu(tkroot)
+ filemenu = Menu(menubar, tearoff=0)
+ filemenu.add_command(label='Quit',
+ command=self.__quit,
+ accelerator='Alt-Q',
+ underline=0)
+ helpmenu = Menu(menubar, name='help', tearoff=0)
+ helpmenu.add_command(label='About Audiopy...',
+ command=self.__popup_about,
+ underline=0)
+ helpmenu.add_command(label='Help...',
+ command=self.__popup_using,
+ underline=0)
+ menubar.add_cascade(label='File',
+ menu=filemenu,
+ underline=0)
+ menubar.add_cascade(label='Help',
+ menu=helpmenu,
+ underline=0)
+ # now create the top level window
+ root = self.__root = Toplevel(tkroot, class_='Audiopy', menu=menubar)
+ root.protocol('WM_DELETE_WINDOW', self.__quit)
+ root.title('audiopy ' + __version__)
+ root.iconname('audiopy ' + __version__)
+ root.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
+ #
+ buttons = []
+ #
+ # where does input come from?
+ frame = Frame(root, bd=1, relief=RAISED)
+ frame.grid(row=1, column=0, sticky='NSEW')
+ label = Label(frame, text='Input From:')
+ label.grid(row=0, column=0, sticky=E)
+ self.__inputvar = IntVar()
+ ##
+ btn = Radiobutton(frame,
+ text='None',
+ variable=self.__inputvar,
+ value=0,
+ command=self.__pushtodev,
+ underline=0)
+ btn.grid(row=0, column=1, sticky=W)
+ root.bind('<Alt-n>', self.__none)
+ root.bind('<Alt-N>', self.__none)
+ if not info.i_avail_ports & MICROPHONE:
+ btn.configure(state=DISABLED)
+ buttons.append(btn)
+ ##
+ btn = Radiobutton(frame,
+ text='Microphone',
+ variable=self.__inputvar,
+ value=MICROPHONE,
+ command=self.__pushtodev,
+ underline=0)
+ btn.grid(row=1, column=1, sticky=W)
+ root.bind('<Alt-m>', self.__mic)
+ root.bind('<Alt-M>', self.__mic)
+ if not info.i_avail_ports & MICROPHONE:
+ btn.configure(state=DISABLED)
+ buttons.append(btn)
+ ##
+ btn = Radiobutton(frame,
+ text='Line In',
+ variable=self.__inputvar,
+ value=LINE_IN,
+ command=self.__pushtodev,
+ underline=5)
+ btn.grid(row=2, column=1, sticky=W)
+ root.bind('<Alt-i>', self.__linein)
+ root.bind('<Alt-I>', self.__linein)
+ if not info.i_avail_ports & LINE_IN:
+ btn.configure(state=DISABLED)
+ buttons.append(btn)
+ ## if SUNAUDIODEV was built on an older version of Solaris, the CD
+ ## input device won't exist
+ try:
+ btn = Radiobutton(frame,
+ text='CD',
+ variable=self.__inputvar,
+ value=CD,
+ command=self.__pushtodev,
+ underline=0)
+ btn.grid(row=3, column=1, sticky=W)
+ root.bind('<Alt-c>', self.__cd)
+ root.bind('<Alt-C>', self.__cd)
+ if not info.i_avail_ports & CD:
+ btn.configure(state=DISABLED)
+ buttons.append(btn)
+ except NameError:
+ pass
+ #
+ # where does output go to?
+ frame = Frame(root, bd=1, relief=RAISED)
+ frame.grid(row=2, column=0, sticky='NSEW')
+ label = Label(frame, text='Output To:')
+ label.grid(row=0, column=0, sticky=E)
+ self.__spkvar = IntVar()
+ btn = Checkbutton(frame,
+ text='Speaker',
+ variable=self.__spkvar,
+ onvalue=SPEAKER,
+ command=self.__pushtodev,
+ underline=0)
+ btn.grid(row=0, column=1, sticky=W)
+ root.bind('<Alt-s>', self.__speaker)
+ root.bind('<Alt-S>', self.__speaker)
+ if not info.o_avail_ports & SPEAKER:
+ btn.configure(state=DISABLED)
+ buttons.append(btn)
+ ##
+ self.__headvar = IntVar()
+ btn = Checkbutton(frame,
+ text='Headphones',
+ variable=self.__headvar,
+ onvalue=HEADPHONE,
+ command=self.__pushtodev,
+ underline=4)
+ btn.grid(row=1, column=1, sticky=W)
+ root.bind('<Alt-p>', self.__headphones)
+ root.bind('<Alt-P>', self.__headphones)
+ if not info.o_avail_ports & HEADPHONE:
+ btn.configure(state=DISABLED)
+ buttons.append(btn)
+ ##
+ self.__linevar = IntVar()
+ btn = Checkbutton(frame,
+ variable=self.__linevar,
+ onvalue=LINE_OUT,
+ text='Line Out',
+ command=self.__pushtodev,
+ underline=0)
+ btn.grid(row=2, column=1, sticky=W)
+ root.bind('<Alt-l>', self.__lineout)
+ root.bind('<Alt-L>', self.__lineout)
+ if not info.o_avail_ports & LINE_OUT:
+ btn.configure(state=DISABLED)
+ buttons.append(btn)
+ #
+ # Fix up widths
+ widest = 0
+ for b in buttons:
+ width = b['width']
+ if width > widest:
+ widest = width
+ for b in buttons:
+ b.configure(width=widest)
+ # root bindings
+ root.bind('<Alt-q>', self.__quit)
+ root.bind('<Alt-Q>', self.__quit)
+ #
+ # Volume
+ frame = Frame(root, bd=1, relief=RAISED)
+ frame.grid(row=3, column=0, sticky='NSEW')
+ label = Label(frame, text='Output Volume:')
+ label.grid(row=0, column=0, sticky=W)
+ self.__scalevar = IntVar()
+ self.__scale = Scale(frame,
+ orient=HORIZONTAL,
+ from_=MIN_GAIN,
+ to=MAX_GAIN,
+ length=200,
+ variable=self.__scalevar,
+ command=self.__volume)
+ self.__scale.grid(row=1, column=0, sticky=EW)
+ #
+ # do we need to poll for changes?
+ self.__needtopoll = 1
+ try:
+ fd = self.__devctl.fileno()
+ self.__needtopoll = 0
+ except AttributeError:
+ pass
+ else:
+ import fcntl
+ import signal
+ import STROPTS
+ # set up the signal handler
+ signal.signal(signal.SIGPOLL, self.__update)
+ fcntl.ioctl(fd, STROPTS.I_SETSIG, STROPTS.S_MSG)
+ self.__update()
+
+ def __quit(self, event=None):
+ self.__devctl.close()
+ self.__root.quit()
+
+ def __popup_about(self, event=None):
+ import tkMessageBox
+ tkMessageBox.showinfo('About Audiopy ' + __version__,
+ '''\
+Audiopy %s
+Control the Solaris audio device
+
+For information
+Contact: Barry A. Warsaw
+Email: bwarsaw@python.org''' % __version__)
+
+ def __popup_using(self, event=None):
+ if not self.__helpwin:
+ self.__helpwin = Helpwin(self.__tkroot, self.__quit)
+ self.__helpwin.deiconify()
+
+
+ def __keepalive(self):
+ # Exercise the Python interpreter regularly so keyboard interrupts get
+ # through.
+ self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
+ if self.__needtopoll:
+ self.__update()
+
+ def __update(self, num=None, frame=None):
+ # It's possible (although I have never seen it) to get an interrupted
+ # system call during the getinfo() call. If so, and we're polling,
+ # don't sweat it because we'll come around again later. Otherwise,
+ # we'll give it a couple of tries and then give up until next time.
+ tries = 0
+ while 1:
+ try:
+ info = self.__devctl.getinfo()
+ break
+ except sunaudiodev.error:
+ if self.__needtopoll or tries > 3:
+ return
+ tries = tries + 1
+ # input
+ self.__inputvar.set(info.i_port)
+ # output
+ self.__spkvar.set(info.o_port & SPEAKER)
+ self.__headvar.set(info.o_port & HEADPHONE)
+ self.__linevar.set(info.o_port & LINE_OUT)
+ # volume
+ self.__scalevar.set(info.o_gain)
+
+ def __pushtodev(self, event=None):
+ info = self.__devctl.getinfo()
+ info.o_port = self.__spkvar.get() + \
+ self.__headvar.get() + \
+ self.__linevar.get()
+ info.i_port = self.__inputvar.get()
+ info.o_gain = self.__scalevar.get()
+ try:
+ self.__devctl.setinfo(info)
+ except sunaudiodev.error, msg:
+ # TBD: what to do? it's probably temporary.
+ pass
+
+ def __getset(self, var, onvalue):
+ if var.get() == onvalue:
+ var.set(0)
+ else:
+ var.set(onvalue)
+ self.__pushtodev()
+
+ def __none(self, event=None):
+ self.__inputvar.set(0)
+ self.__pushtodev()
+
+ def __mic(self, event=None):
+ self.__getset(self.__inputvar, MICROPHONE)
+
+ def __linein(self, event=None):
+ self.__getset(self.__inputvar, LINE_IN)
+
+ def __cd(self, event=None):
+ self.__getset(self.__inputvar, CD)
+
+ def __speaker(self, event=None):
+ self.__getset(self.__spkvar, SPEAKER)
+
+ def __headphones(self, event=None):
+ self.__getset(self.__headvar, HEADPHONE)
+
+ def __lineout(self, event=None):
+ self.__getset(self.__linevar, LINE_OUT)
+
+ def __volume(self, event=None):
+ self.__pushtodev()
+
+ def start(self):
+ self.__keepalive()
+ self.__tkroot.mainloop()
+
+
+
+class Helpwin:
+ def __init__(self, master, quitfunc):
+ from Tkinter import *
+ self.__root = root = Toplevel(master, class_='Audiopy')
+ root.protocol('WM_DELETE_WINDOW', self.__withdraw)
+ root.title('Audiopy Help Window')
+ root.iconname('Audiopy Help Window')
+ root.bind('<Alt-q>', quitfunc)
+ root.bind('<Alt-Q>', quitfunc)
+ root.bind('<Alt-w>', self.__withdraw)
+ root.bind('<Alt-W>', self.__withdraw)
+
+ # more elaborate help is available in the README file
+ readmefile = os.path.join(sys.path[0], 'README')
+ try:
+ fp = None
+ try:
+ fp = open(readmefile)
+ contents = fp.read()
+ # wax the last page, it contains Emacs cruft
+ i = contents.rfind('\f')
+ if i > 0:
+ contents = contents[:i].rstrip()
+ finally:
+ if fp:
+ fp.close()
+ except IOError:
+ sys.stderr.write("Couldn't open audiopy's README, "
+ 'using docstring instead.\n')
+ contents = __doc__ % globals()
+
+ self.__text = text = Text(root, relief=SUNKEN,
+ width=80, height=24)
+ text.insert(0.0, contents)
+ scrollbar = Scrollbar(root)
+ scrollbar.pack(fill=Y, side=RIGHT)
+ text.pack(fill=BOTH, expand=YES)
+ text.configure(yscrollcommand=(scrollbar, 'set'))
+ scrollbar.configure(command=(text, 'yview'))
+
+ def __withdraw(self, event=None):
+ self.__root.withdraw()
+
+ def deiconify(self):
+ self.__root.deiconify()
+
+
+
+
+def usage(code, msg=''):
+ print __doc__ % globals()
+ if msg:
+ print msg
+ sys.exit(code)
+
+
+def main():
+ #
+ # Open up the audio control device and query for the current output
+ # device
+ device = sunaudiodev.open('control')
+
+ if len(sys.argv) == 1:
+ # GUI
+ w = MainWindow(device)
+ try:
+ w.start()
+ except KeyboardInterrupt:
+ pass
+ return
+
+ # spec: LONG OPT, SHORT OPT, 0=input,1=output, MASK
+ options = [('--microphone', '-m', 0, MICROPHONE),
+ ('--linein', '-i', 0, LINE_IN),
+ ('--headphones', '-p', 1, HEADPHONE),
+ ('--speaker', '-s', 1, SPEAKER),
+ ('--lineout', '-o', 1, LINE_OUT),
+ ]
+ # See the comment above about `CD'
+ try:
+ options.append(('--cd', '-c', 0, CD))
+ except NameError:
+ pass
+
+ info = device.getinfo()
+ # first get the existing values
+ i = 0
+ while i < len(sys.argv)-1:
+ i = i + 1
+ arg = sys.argv[i]
+ if arg in ('-h', '--help'):
+ usage(0)
+ # does not return
+ elif arg in ('-g', '--gain'):
+ gainspec = '<missing>'
+ try:
+ gainspec = sys.argv[i+1]
+ gain = int(gainspec)
+ except (ValueError, IndexError):
+ usage(1, 'Bad gain specification: ' + gainspec)
+ info.o_gain = gain
+ i = i + 1
+ continue
+ elif arg in ('-v', '--version'):
+ print '''\
+audiopy -- a program to control the Solaris audio device.
+Contact: Barry Warsaw
+Email: bwarsaw@python.org
+Version: %s''' % __version__
+ sys.exit(0)
+ for long, short, io, mask in options:
+ if arg in (long, short):
+ # toggle the option
+ if io == 0:
+ info.i_port = info.i_port ^ mask
+ else:
+ info.o_port = info.o_port ^ mask
+ break
+ val = None
+ try:
+ if arg[:len(long)+1] == long+'=':
+ val = int(arg[len(long)+1:])
+ elif arg[:len(short)+1] == short+'=':
+ val = int(arg[len(short)+1:])
+ except ValueError:
+ usage(1, msg='Invalid option: ' + arg)
+ # does not return
+ if val == 0:
+ if io == 0:
+ info.i_port = info.i_port & ~mask
+ else:
+ info.o_port = info.o_port & ~mask
+ break
+ elif val == 1:
+ if io == 0:
+ info.i_port = info.i_port | mask
+ else:
+ info.o_port = info.o_port | mask
+ break
+ # else keep trying next option
+ else:
+ usage(1, msg='Invalid option: ' + arg)
+ # now set the values
+ try:
+ device.setinfo(info)
+ except sunaudiodev.error, (code, msg):
+ if code <> errno.EINVAL:
+ raise
+ device.close()
+
+
+
+if __name__ == '__main__':
+ main()