diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
commit | 458120dd40db6b4df55a4e96b650e16798ef06a0 (patch) | |
tree | 8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/src/cmd/python/Tools/audiopy | |
parent | 3a742c699f6806c1145aea5149bf15de15a0afd7 (diff) |
add hg and python
Diffstat (limited to 'sys/src/cmd/python/Tools/audiopy')
-rw-r--r-- | sys/src/cmd/python/Tools/audiopy/README | 112 | ||||
-rwxr-xr-x | sys/src/cmd/python/Tools/audiopy/audiopy | 507 |
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() |