diff options
Diffstat (limited to 'demo/sgi/audio_stdwin/jukebox.py')
| -rwxr-xr-x | demo/sgi/audio_stdwin/jukebox.py | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/demo/sgi/audio_stdwin/jukebox.py b/demo/sgi/audio_stdwin/jukebox.py new file mode 100755 index 0000000..5267d73 --- /dev/null +++ b/demo/sgi/audio_stdwin/jukebox.py @@ -0,0 +1,321 @@ +#! /ufs/guido/bin/sgi/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.cat(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.cat(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() |
