summaryrefslogtreecommitdiffstats
path: root/Demo/stdwin
diff options
context:
space:
mode:
Diffstat (limited to 'Demo/stdwin')
-rwxr-xr-xDemo/stdwin/jukebox.py314
1 files changed, 314 insertions, 0 deletions
diff --git a/Demo/stdwin/jukebox.py b/Demo/stdwin/jukebox.py
new file mode 100755
index 0000000..fba5d71
--- /dev/null
+++ b/Demo/stdwin/jukebox.py
@@ -0,0 +1,314 @@
+#! /ufs/guido/bin/sgi/python
+
+# XXX This file is being hacked -- some functionality has been taken out!
+
+# 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 commands
+import getopt
+import os
+import rand
+import stdwin
+from stdwinevents import *
+import string
+import sys
+import tempfile
+
+from WindowParent import WindowParent
+from HVSplit import VSplit
+from Buttons import PushButton
+from Sliders import ComplexSlider
+
+# Pathnames
+
+DEF_DB = '/usr/local/sounds/aiff' # Default directory of sounds
+SOX = '/usr/local/sox' # Sound format conversion program
+SFPLAY = '/usr/sbin/sfplay' # Sound playing program
+
+
+# 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.busy = 0 # Set while asynchronous playing is active
+ G.windows = [] # List of open windows, except control
+ G.mode = '' # File type (default any that sfplay knows)
+ G.rate = 0 # Sampling rate (default " " " ")
+ G.tempprefix = tempfile.mktemp()
+ #
+ try:
+ optlist, args = getopt.getopt(sys.argv[1:], 'dr:st:')
+ except getopt.error, msg:
+ sys.stdout = sys.stderr
+ print msg
+ print 'usage: jukebox [-d] [-s] [-t type] [-r rate]'
+ print ' -d debugging'
+ print ' -s synchronous playing'
+ print ' -t type file type'
+ print ' -r rate sampling rate'
+ sys.exit(2)
+ #
+ for optname, optarg in optlist:
+ if optname == '-d':
+ G.debug = 1
+ elif optname == '-r':
+ G.rate = int(eval(optarg))
+ elif optname == '-s':
+ G.synchronous = 1
+ elif optname == '-t':
+ G.mode = optarg
+ #
+ if not args:
+ args = [DEF_DB]
+ #
+ G.cw = opencontrolwindow()
+ for dirname in args:
+ G.windows.append(openlistwindow(dirname))
+ #
+ #
+ try:
+ maineventloop()
+ finally:
+ clearcache()
+ killchild()
+
+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
+ if type == WE_TIMER:
+ checkchild()
+ if G.busy:
+ G.cw.win.settimer(1)
+ else:
+ 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
+
+def checkchild():
+ if G.busy:
+ waitchild(1)
+
+def killchild():
+ if G.busy:
+ os.kill(G.busy, 9)
+ waitchild(0)
+
+def waitchild(options):
+ pid, sts = os.wait(G.busy, options)
+ if pid == G.busy:
+ G.busy = 0
+ G.stop.enable(0)
+
+
+# Control window -- to set gain and cancel play operations in progress
+
+def opencontrolwindow():
+ stdwin.setdefscrollbars(0, 0)
+ cw = WindowParent().create('Jukebox', (0, 0))
+ v = VSplit().create(cw)
+ #
+ stop = PushButton().definetext(v, 'Stop')
+ stop.hook = stop_hook
+ stop.enable(0)
+ G.stop = stop
+ #
+ cw.realize()
+ return cw
+
+def stop_hook(self):
+ killchild()
+
+
+# List windows -- to display list of files and subdirectories
+
+def openlistwindow(dirname):
+ list = os.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 os.path.isdir(os.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))
+ stdwin.setdefscrollbars(0, 1)
+ 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):
+## (left, top), (right, bottom) = 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)
+ d.close()
+
+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)
+ d.close()
+ if type == WE_MOUSE_DOWN and clicks >= 2 and i >= 0:
+ setcursors('watch')
+ name = os.path.join(w.dirname, w.list[i])
+ if name[-1:] == '/':
+ if clicks == 2:
+ G.windows.append(openlistwindow(name[:-1]))
+ else:
+ playfile(name)
+ setcursors('cross')
+
+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
+
+def setcursors(cursor):
+ for w in G.windows:
+ w.setwincursor(cursor)
+ G.cw.win.setwincursor(cursor)
+
+
+# Playing tools
+
+cache = {}
+
+def clearcache():
+ for x in cache.keys():
+ try:
+ sts = os.system('rm -f ' + cache[x])
+ if sts:
+ print cmd
+ print 'Exit status', sts
+ except:
+ print cmd
+ print 'Exception?!'
+ del cache[x]
+
+def playfile(name):
+ killchild()
+ if G.mode in ('', 'au', 'aiff'):
+ tempname = name
+ elif cache.has_key(name):
+ tempname = cache[name]
+ else:
+ tempname = G.tempprefix + `rand.rand()` + '.aiff'
+ cmd = SOX
+ if G.mode <> '' and G.mode <> 'sox':
+ cmd = cmd + ' -t ' + G.mode
+ cmd = cmd + ' ' + commands.mkarg(name)
+ cmd = cmd + ' -t aiff'
+ if G.rate:
+ cmd = cmd + ' -r ' + `G.rate`
+ cmd = cmd + ' ' + tempname
+ if G.debug: print cmd
+ sts = os.system(cmd)
+ if sts:
+ print cmd
+ print 'Exit status', sts
+ stdwin.fleep()
+ return
+ cache[name] = tempname
+ pid = os.fork()
+ if pid == 0:
+ # Child
+ os.exec(SFPLAY, [SFPLAY, '-r', tempname])
+ # NOTREACHED
+ # Parent
+ if G.synchronous:
+ sts = os.wait(pid, 0)
+ else:
+ G.busy = pid
+ G.stop.enable(1)
+ G.cw.win.settimer(1)
+
+main()