Import Upstream version 2.7.18

This commit is contained in:
geos_one
2025-08-15 16:28:06 +02:00
commit ba1f69ab39
4521 changed files with 1778434 additions and 0 deletions

112
Tools/audiopy/README Normal file
View File

@@ -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:

507
Tools/audiopy/audiopy Executable file
View File

@@ -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()