Kaydet (Commit) 715a6531 authored tarafından Guido van Rossum's avatar Guido van Rossum

Initial revision

üst 4a5ab81b
Programs that demonstrate the use of the audio device on the SGI 4D/25.
These require the built-in module 'audio'.
XXX This hardware is already obsolete; see ../al for examples of audio
XXX on the Indigo and 4D/35.
play Read a sound sample from a file and play it through the
speaker. Options to set volume, sampling rate etc.
#! /usr/local/python
import sys
import audio
import string
import getopt
import auds
debug = []
DEF_RATE = 3
def main():
#
gain = 100
rate = 0
starter = audio.write
stopper = 0
#
optlist, args = getopt.getopt(sys.argv[1:], 'adg:r:')
#
for optname, optarg in optlist:
if 0:
pass
elif optname == '-d':
debug.append(1)
elif optname == '-g':
gain = string.atoi(optarg)
if not (0 < gain < 256):
raise optarg.error, '-g gain out of range'
elif optname == '-r':
rate = string.atoi(optarg)
if not (1 <= rate <= 3):
raise optarg.error, '-r rate out of range'
elif optname == '-a':
starter = audio.start_playing
stopper = audio.wait_playing
#
audio.setoutgain(gain)
audio.setrate(rate)
#
if not args:
play(starter, rate, auds.loadfp(sys.stdin))
else:
real_stopper = 0
for file in args:
if real_stopper:
real_stopper()
play(starter, rate, auds.load(file))
real_stopper = stopper
def play(starter, rate, data):
magic = data[:4]
if magic == '0008':
mrate = 3
elif magic == '0016':
mrate = 2
elif magic == '0032':
mrate = 1
else:
mrate = 0
if mrate:
data = data[4:]
else:
mrate = DEF_RATE
if not rate: rate = mrate
audio.setrate(rate)
starter(data)
try:
main()
finally:
audio.setoutgain(0)
audio.done()
Three programs that provide a user interface based upon STDWIN to the
audio device of the SGI 4D/25. These scripts also demonstrate the power
of a set of window interface classes implemented in Python that simplify
the construction of all sorts of buttons, etc.
XXX This hardware is already obsolete; see ../al for examples of audio
XXX on the Indigo and 4D/35.
jukebox Browses a directory full of sound samples and lets you
play selected ones. (Probably not fully functional, it
requires a conversion program.)
rec A tape recorder that lets you record a sound sample,
play it back, and save it to a file. Various options to
set sampling rate, volume etc. When idle it doubles
as a VU meter.
vumeter A VU meter that displays a history of the volume of
sound recently sampled from the microphone.
#! /usr/local/python
# JUKEBOX: browse directories full of sampled sound files.
#
# One or more "list windows" display the files and subdirectories of
# the arguments. Double-clicking on a subdirectory opens a new window
# displaying its contents (and so on recursively). Double clicking
# on a file plays it as a sound file (assuming it is one).
#
# Playing is asynchronous: the application keeps listening to events
# while the sample is playing, so you can change the volume (gain)
# during playing, cancel playing or start a new sample right away.
#
# The control window displays the current output gain and a primitive
# "stop button" to cancel the current play request.
#
# Sound files must currently be in Dik Winter's compressed Mac format.
# Since decompression is costly, decompressed samples are saved in
# /usr/tmp/@j* until the application is left. The files are read
# afresh each time, though.
import audio
import sunaudio
import commands
import getopt
import path
import posix
import rand
import stdwin
from stdwinevents import *
import string
import sys
from WindowParent import WindowParent
from HVSplit import VSplit
from Buttons import PushButton
from Sliders import ComplexSlider
# Pathnames
HOME_BIN_SGI = '/ufs/guido/bin/sgi/' # Directory where macsound2sgi lives
DEF_DB = '/ufs/dik/sounds/Mac/HCOM' # Default directory of sounds
# Global variables
class struct: pass # Class to define featureless structures
G = struct() # Holds writable global variables
# Main program
def main():
G.synchronous = 0 # If set, use synchronous audio.write()
G.debug = 0 # If set, print debug messages
G.gain = 75 # Output gain
G.rate = 3 # Sampling rate
G.busy = 0 # Set while asynchronous playing is active
G.windows = [] # List of open windows (except control)
G.mode = 'mac' # Macintosh mode
G.tempprefix = '/usr/tmp/@j' + `rand.rand()` + '-'
#
optlist, args = getopt.getopt(sys.argv[1:], 'dg:r:sSa')
for optname, optarg in optlist:
if optname == '-d':
G.debug = 1
elif optname == '-g':
G.gain = string.atoi(optarg)
if not (0 < G.gain < 256):
raise optarg.error, '-g gain out of range'
elif optname == '-r':
G.rate = string.atoi(optarg)
if not (1 <= G.rate <= 3):
raise optarg.error, '-r rate out of range'
elif optname == '-s':
G.synchronous = 1
elif optname == '-S':
G.mode = 'sgi'
elif optname == '-a':
G.mode = 'sun'
#
if not args:
args = [DEF_DB]
#
G.cw = opencontrolwindow()
for dirname in args:
G.windows.append(openlistwindow(dirname))
#
#
savegain = audio.getoutgain()
try:
# Initialize stdaudio
audio.setoutgain(0)
audio.start_playing('')
dummy = audio.wait_playing()
audio.setoutgain(0)
maineventloop()
finally:
audio.setoutgain(savegain)
audio.done()
clearcache()
def maineventloop():
mouse_events = WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP
while G.windows:
type, w, detail = event = stdwin.getevent()
if w == G.cw.win:
if type == WE_CLOSE:
return
G.cw.dispatch(event)
else:
if type == WE_DRAW:
w.drawproc(w, detail)
elif type in mouse_events:
w.mouse(w, type, detail)
elif type == WE_CLOSE:
w.close(w)
del w, event
else:
if G.debug: print type, w, detail
# Control window -- to set gain and cancel play operations in progress
def opencontrolwindow():
cw = WindowParent().create('Jukebox', (0, 0))
v = VSplit().create(cw)
#
gain = ComplexSlider().define(v)
gain.setminvalmax(0, G.gain, 255)
gain.settexts(' ', ' ')
gain.sethook(gain_setval_hook)
#
stop = PushButton().definetext(v, 'Stop')
stop.hook = stop_hook
#
cw.realize()
return cw
def gain_setval_hook(self):
G.gain = self.val
if G.busy: audio.setoutgain(G.gain)
def stop_hook(self):
if G.busy:
audio.setoutgain(0)
dummy = audio.stop_playing()
G.busy = 0
# List windows -- to display list of files and subdirectories
def openlistwindow(dirname):
list = posix.listdir(dirname)
list.sort()
i = 0
while i < len(list):
if list[i] == '.' or list[i] == '..':
del list[i]
else:
i = i+1
for i in range(len(list)):
name = list[i]
if path.isdir(path.join(dirname, name)):
list[i] = list[i] + '/'
width = maxwidth(list)
width = width + stdwin.textwidth(' ') # XXX X11 stdwin bug workaround
height = len(list) * stdwin.lineheight()
stdwin.setdefwinsize(width, min(height, 500))
w = stdwin.open(dirname)
stdwin.setdefwinsize(0, 0)
w.setdocsize(width, height)
w.drawproc = drawlistwindow
w.mouse = mouselistwindow
w.close = closelistwindow
w.dirname = dirname
w.list = list
w.selected = -1
return w
def maxwidth(list):
width = 1
for name in list:
w = stdwin.textwidth(name)
if w > width: width = w
return width
def drawlistwindow(w, area):
d = w.begindrawing()
d.erase((0, 0), (1000, 10000))
lh = d.lineheight()
h, v = 0, 0
for name in w.list:
d.text((h, v), name)
v = v + lh
showselection(w, d)
def hideselection(w, d):
if w.selected >= 0:
invertselection(w, d)
def showselection(w, d):
if w.selected >= 0:
invertselection(w, d)
def invertselection(w, d):
lh = d.lineheight()
h1, v1 = p1 = 0, w.selected*lh
h2, v2 = p2 = 1000, v1 + lh
d.invert(p1, p2)
def mouselistwindow(w, type, detail):
(h, v), clicks, button = detail[:3]
d = w.begindrawing()
lh = d.lineheight()
if 0 <= v < lh*len(w.list):
i = v / lh
else:
i = -1
if w.selected <> i:
hideselection(w, d)
w.selected = i
showselection(w, d)
if type == WE_MOUSE_DOWN and clicks >= 2 and i >= 0:
name = path.join(w.dirname, w.list[i])
if name[-1:] == '/':
if clicks == 2:
G.windows.append(openlistwindow(name[:-1]))
else:
playfile(name)
def closelistwindow(w):
remove(G.windows, w)
def remove(list, item):
for i in range(len(list)):
if list[i] == item:
del list[i]
break
# Playing tools
cache = {}
def clearcache():
for x in cache.keys():
try:
sts = posix.system('rm -f ' + cache[x])
if sts:
print cmd
print 'Exit status', sts
except:
print cmd
print 'Exception?!'
del cache[x]
def playfile(name):
if G.mode <> 'mac':
tempname = name
elif cache.has_key(name):
tempname = cache[name]
else:
tempname = G.tempprefix + `rand.rand()`
cmd = HOME_BIN_SGI + 'macsound2sgi'
cmd = cmd + ' ' + commands.mkarg(name)
cmd = cmd + ' >' + tempname
if G.debug: print cmd
sts = posix.system(cmd)
if sts:
print cmd
print 'Exit status', sts
stdwin.fleep()
return
cache[name] = tempname
fp = open(tempname, 'r')
try:
hdr = sunaudio.gethdr(fp)
except sunaudio.error, msg:
hdr = ()
if hdr:
data_size = hdr[0]
data = fp.read(data_size)
# XXX this doesn't work yet, need to convert from uLAW!!!
del fp
else:
del fp
data = readfile(tempname)
if G.debug: print len(data), 'bytes read from', tempname
if G.busy:
G.busy = 0
dummy = audio.stop_playing()
#
# Completely reset the audio device
audio.setrate(G.rate)
audio.setduration(0)
audio.setoutgain(G.gain)
#
if G.synchronous:
audio.write(data)
audio.setoutgain(0)
else:
try:
audio.start_playing(data)
G.busy = 1
except:
stdwin.fleep()
del data
def readfile(filename):
return readfp(open(filename, 'r'))
def readfp(fp):
data = ''
while 1:
buf = fp.read(102400) # Reads most samples in one fell swoop
if not buf:
return data
data = data + buf
main()
#! /ufs/guido/bin/sgi/python
import sys
import audio
import stdwin
import string
import getopt
from stdwinevents import *
from Buttons import *
from Sliders import *
#from Soundogram import Soundogram
from VUMeter import VUMeter
from WindowParent import WindowParent, MainLoop
from HVSplit import HSplit, VSplit
class TimeOutToggleButton(ToggleButton):
def define(self, parent):
self = ToggleButton.define(self, parent)
self.parent.need_timer(self)
self.timer_hook = 0
return self
def timer(self):
if self.timer_hook:
self.timer_hook(self)
K = 1024
BUFSIZE = 30*8*K
Rates = [0, 32*K, 16*K, 8*K]
Magics = ['', '0032', '0016', '0008']
class Struct: pass
G = Struct()
def main():
#
# Turn off scroll bars
#
stdwin.setdefscrollbars(0, 0)
#
# Set default state
#
G.gain = 60
G.rate = 3
G.nomuting = 0
G.savefile = '@rec'
#
# Set default values
#
G.data = ''
G.playing = 0
G.recording = 0
G.sogram = 0
#
# Parse options
#
optlist, args = getopt.getopt(sys.argv[1:], 'mdg:r:')
#
for optname, optarg in optlist:
if 0: # (So all cases start with elif)
pass
elif optname == '-d':
G.debug = 1
elif optname == '-g':
G.gain = string.atoi(optarg)
if not (0 < G.gain < 256):
raise optarg.error, '-g gain out of range'
elif optname == '-m':
G.nomuting = (not G.nomuting)
elif optname == '-r':
G.rate = string.atoi(optarg)
if not (1 <= G.rate <= 3):
raise optarg.error, '-r rate out of range'
#
if args:
G.savefile = args[0]
#
# Initialize the sound package
#
audio.setoutgain(G.nomuting * G.gain) # Silence the speaker
audio.setrate(G.rate)
#
# Create the WindowParent and VSplit
#
G.window = WindowParent().create('Recorder', (0, 0))
w = G.vsplit = VSplit().create(G.window)
#
# VU-meter
#
G.vubtn = VUMeter().define(w)
#
# Radiobuttons for rates
#
r1btn = RadioButton().definetext(w, '32 K/sec')
r1btn.on_hook = rate_hook
r1btn.rate = 1
#
r2btn = RadioButton().definetext(w, '16 K/sec')
r2btn.on_hook = rate_hook
r2btn.rate = 2
#
r3btn = RadioButton().definetext(w, '8 K/sec')
r3btn.on_hook = rate_hook
r3btn.rate = 3
#
radios = [r1btn, r2btn, r3btn]
r1btn.group = r2btn.group = r3btn.group = radios
for r in radios:
if r.rate == G.rate: r.select(1)
#
# Other controls
#
G.recbtn = TimeOutToggleButton().definetext(w, 'Record')
G.recbtn.on_hook = record_on_hook
G.recbtn.timer_hook = record_timer_hook
G.recbtn.off_hook = record_off_hook
#
G.mutebtn = CheckButton().definetext(w, 'Mute')
G.mutebtn.select(not G.nomuting)
G.mutebtn.hook = mute_hook
#
G.playbtn = TimeOutToggleButton().definetext(w, 'Playback')
G.playbtn.on_hook = play_on_hook
G.playbtn.timer_hook = play_timer_hook
G.playbtn.off_hook = play_off_hook
#
G.gainbtn = ComplexSlider().define(w)
G.gainbtn.settexts(' Volume: ', ' ')
G.gainbtn.setminvalmax(0, G.gain, 255)
G.gainbtn.sethook(gain_hook)
#
G.sizebtn = Label().definetext(w, `len(G.data)` + ' bytes')
#
#G.showbtn = PushButton().definetext(w, 'Sound-o-gram...')
#G.showbtn.hook = show_hook
#
G.savebtn = PushButton().definetext(w, 'Save...')
G.savebtn.hook = save_hook
#
G.quitbtn = PushButton().definetext(w, 'Quit')
G.quitbtn.hook = quit_hook
G.playbtn.enable(0)
G.savebtn.enable(0)
#G.showbtn.enable(0)
start_vu()
G.window.realize()
#
# Event loop
#
MainLoop()
# XXX Disabled...
def show_hook(self):
savetext = self.text
self.settext('Be patient...')
close_sogram()
stdwin.setdefwinsize(400, 300)
win = stdwin.open('Sound-o-gram')
G.sogram = Soundogram().define(win, G.data)
win.buttons = [G.sogram]
self.settext(savetext)
def close_sogram():
if G.sogram:
# Break circular references
G.sogram.win.buttons[:] = []
del G.sogram.win
G.sogram = 0
def mute_hook(self):
G.nomuting = (not self.selected)
audio.setoutgain(G.nomuting * G.gain)
def rate_hook(self):
G.rate = self.rate
audio.setrate(G.rate)
def record_on_hook(self):
stop_vu()
close_sogram()
audio.setrate(G.rate)
audio.setoutgain(G.nomuting * G.gain)
audio.start_recording(BUFSIZE)
G.recording = 1
G.playbtn.enable(0)
G.window.settimer(10 * BUFSIZE / Rates[G.rate])
def record_timer_hook(self):
if G.recording:
if audio.poll_recording():
self.hilite(0)
record_off_hook(self)
else:
self.parent.settimer(5)
def record_off_hook(self):
if not G.recording:
return
G.data = audio.stop_recording()
G.recording = 0
G.sizebtn.settext(`len(G.data)` + ' bytes')
audio.setoutgain(G.nomuting * G.gain)
G.playbtn.enable((len(G.data) > 0))
G.savebtn.enable((len(G.data) > 0))
#G.showbtn.enable((len(G.data) > 0))
G.window.settimer(0)
start_vu()
def play_on_hook(self):
stop_vu()
audio.setrate(G.rate)
audio.setoutgain(G.gain)
audio.start_playing(G.data)
G.playing = 1
G.recbtn.enable(0)
G.window.settimer(max(10 * len(G.data) / Rates[G.rate], 1))
def play_timer_hook(self):
if G.playing:
if audio.poll_playing():
self.hilite(0)
play_off_hook(self)
else:
self.parent.settimer(5)
def play_off_hook(self):
if not G.playing:
return
x = audio.stop_playing()
G.playing = 0
audio.setoutgain(G.nomuting * G.gain)
G.recbtn.enable(1)
G.window.settimer(0)
start_vu()
def gain_hook(self):
G.gain = self.val
if G.playing or G.nomuting: audio.setoutgain(G.gain)
def save_hook(self):
if not G.data:
stdwin.fleep()
else:
prompt = 'Store sampled data on file: '
try:
G.savefile = stdwin.askfile(prompt, G.savefile, 1)
except KeyboardInterrupt:
return
try:
fp = open(G.savefile, 'w')
fp.write(Magics[G.rate] + G.data)
except:
stdwin.message('Cannot create ' + file)
def stop_vu():
G.vubtn.stop()
def start_vu():
G.vubtn.start()
def quit_hook(self):
G.window.delayed_destroy()
try:
main()
finally:
audio.setoutgain(0)
#! /usr/local/python
import audio
import stdwin
from VUMeter import VUMeter
from WindowParent import WindowParent
import MainLoop
NBUFS=20
BUFSIZE = NBUFS*48
SCALE=128
class MyVUMeter(VUMeter):
def init_reactivity(self):
self.parent.need_mouse(self)
def mouse_down(self, detail):
if self.enabled:
self.stop()
else:
self.start()
def mouse_move(self, detail): pass
def mouse_up(self, detail): pass
def main():
audio.setrate(3)
audio.setoutgain(0)
w = WindowParent().create('VU Meter', (200, 100))
v = MyVUMeter().define(w)
v.start()
w.realize()
while 1:
w.dispatch(stdwin.getevent())
main()
Magic: 12321
Internal Form Definition File
(do not change)
Number of forms: 1
=============== FORM ===============
Name: main_form
Width: 170.000000
Height: 190.000000
Number of Objects: 4
--------------------
class: 1
type: 1
box: 0.000000 0.000000 170.000000 190.000000
boxtype: 1
colors: 47 47
alignment: 4
style: 0
size: 11.000000
lcol: 0
label:
name:
callback:
argument:
--------------------
class: 11
type: 0
box: 10.000000 140.000000 150.000000 40.000000
boxtype: 1
colors: 47 47
alignment: 4
style: 0
size: 11.000000
lcol: 0
label: Button 1
name: button1
callback: button1CB
argument: 0
--------------------
class: 11
type: 0
box: 10.000000 100.000000 150.000000 40.000000
boxtype: 1
colors: 47 47
alignment: 4
style: 0
size: 11.000000
lcol: 0
label: Button 2
name: button2
callback: button2CB
argument: 0
--------------------
class: 11
type: 6
box: 10.000000 10.000000 150.000000 40.000000
boxtype: 1
colors: 47 47
alignment: 4
style: 0
size: 11.000000
lcol: 0
label: EXIT
name: exitbutton
callback: exitbuttonCB
argument: 0
==============================
create_the_forms
#
# Example 2 - Using fl in python with callbacks.
#
# The form is named 'main_form' and resides on file 'test_cb.fd'.
# It has three objects named button1, button2 and exitbutton.
# All buttons have callbacks with the same names as their corresponding
# buttons but with CB appended.
#
import fl # The forms library
import FL # Symbolic constants for the above
import flp # The module to parse .fd files
import sys
# The following struct is created to hold the instance variables
# main_form, button1, button2 and exitbutton.
class myform():
#
# The init function parses and creates the form, but doesn't
# display it (yet).
def init(self, number):
#
# First we parse the form
parsetree = flp.parse_form('test_cb', 'main_form')
#
# Next we create it
flp.create_full_form(self, parsetree)
# And keep our number
self.number = number
return self
#
# The show function displays the form. It doesn't do any interaction,
# though.
def show(self):
self.main_form.show_form(FL.PLACE_SIZE, 1, '')
# The callback functions
def button1CB(self, obj, arg):
print 'Button 1 pressed on form', self.number
def button2CB(self, obj, arg):
print 'Button 2 pressed on form', self.number
def exitbuttonCB(self, obj, arg):
print 'Ok, bye bye'
sys.exit(0)
#
# The main program. Instantiate two variables of the forms class
# and interact with them.
form1 = myform().init(1)
form2 = myform().init(2)
form1.show()
form2.show()
obj = fl.do_forms()
print 'do_forms() returned. This should not happen. obj=', obj
Magic: 12321
Internal Form Definition File
(do not change)
Number of forms: 1
=============== FORM ===============
Name: main_form
Width: 170.000000
Height: 190.000000
Number of Objects: 4
--------------------
class: 1
type: 1
box: 0.000000 0.000000 170.000000 190.000000
boxtype: 1
colors: 47 47
alignment: 4
style: 0
size: 11.000000
lcol: 0
label:
name:
callback:
argument:
--------------------
class: 11
type: 0
box: 10.000000 140.000000 150.000000 40.000000
boxtype: 1
colors: 47 47
alignment: 4
style: 0
size: 11.000000
lcol: 0
label: Button 1
name: button1
callback:
argument:
--------------------
class: 11
type: 0
box: 10.000000 100.000000 150.000000 40.000000
boxtype: 1
colors: 47 47
alignment: 4
style: 0
size: 11.000000
lcol: 0
label: Button 2
name: button2
callback:
argument:
--------------------
class: 11
type: 6
box: 10.000000 10.000000 150.000000 40.000000
boxtype: 1
colors: 47 47
alignment: 4
style: 0
size: 11.000000
lcol: 0
label: EXIT
name: exitbutton
callback:
argument:
==============================
create_the_forms
#
# Example 1 - Using fl in python without callbacks.
#
# The form is named 'main_form' and resides on file 'test_nocb.fd'.
# It has three objects named button1, button2 and exitbutton.
#
import fl # The forms library
import FL # Symbolic constants for the above
import flp # The module to parse .fd files
import sys
# The following struct is created to hold the instance variables
# main_form, button1, button2 and exitbutton.
class struct(): pass
container = struct()
#
# We now first parse the forms file
parsetree = flp.parse_form('test_nocb', 'main_form')
#
# Next we create it
flp.create_full_form(container, parsetree)
#
# And display it
container.main_form.show_form(FL.PLACE_MOUSE, 1, '')
#
# And interact until the exit button is pressed
while 1:
selected_obj = fl.do_forms()
if selected_obj == container.button1:
print 'Button 1 selected'
elif selected_obj == container.button2:
print 'Button 2 selected'
elif selected_obj == container.exitbutton:
print 'Ok, bye bye'
sys.exit(0)
else:
print 'do_forms() returned unknown object ', selected_obj
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment