aboutsummaryrefslogtreecommitdiff
path: root/demo/sgi/audio_stdwin/jukebox.py
diff options
context:
space:
mode:
Diffstat (limited to 'demo/sgi/audio_stdwin/jukebox.py')
-rwxr-xr-xdemo/sgi/audio_stdwin/jukebox.py321
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()