mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
Now uses module 'sndhdr' to recognize most sound header types,
guess raw file parameters, add Rate menu, call SOX to convert file types or sampling rates that sfplay doesn't support.
This commit is contained in:
parent
cb4b2959f8
commit
157e3f8a11
1 changed files with 119 additions and 44 deletions
|
@ -1,6 +1,6 @@
|
||||||
#! /ufs/guido/bin/sgi/python
|
#! /usr/local/python
|
||||||
|
|
||||||
# XXX This file is being hacked -- some functionality has been taken out!
|
# XXX This only works on SGIs running IRIX 4.0 or higher
|
||||||
|
|
||||||
# JUKEBOX: browse directories full of sampled sound files.
|
# JUKEBOX: browse directories full of sampled sound files.
|
||||||
#
|
#
|
||||||
|
@ -9,17 +9,17 @@
|
||||||
# displaying its contents (and so on recursively). Double clicking
|
# displaying its contents (and so on recursively). Double clicking
|
||||||
# on a file plays it as a sound file (assuming it is one).
|
# on a file plays it as a sound file (assuming it is one).
|
||||||
#
|
#
|
||||||
# Playing is asynchronous: the application keeps listening to events
|
# Playing is asynchronous: the application keeps listening for events
|
||||||
# while the sample is playing, so you can change the volume (gain)
|
# while the sample is playing, so you can cancel playing or start a
|
||||||
# during playing, cancel playing or start a new sample right away.
|
# new sample right away. Synchronous playing is available through the
|
||||||
|
# -s option.
|
||||||
#
|
#
|
||||||
# The control window displays the current output gain and a primitive
|
# The control window displays a "stop button" that cancel the current
|
||||||
# "stop button" to cancel the current play request.
|
# play request.
|
||||||
#
|
#
|
||||||
# Sound files must currently be in Dik Winter's compressed Mac format.
|
# Most sound file formats recognized by SOX or SFPLAY are recognized.
|
||||||
# Since decompression is costly, decompressed samples are saved in
|
# Since conversion is costly, converted files are cached in
|
||||||
# /usr/tmp/@j* until the application is left. The files are read
|
# /usr/tmp/@j* until the user quits.
|
||||||
# afresh each time, though.
|
|
||||||
|
|
||||||
import commands
|
import commands
|
||||||
import getopt
|
import getopt
|
||||||
|
@ -32,13 +32,11 @@ import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from WindowParent import WindowParent
|
from WindowParent import WindowParent
|
||||||
from HVSplit import VSplit
|
|
||||||
from Buttons import PushButton
|
from Buttons import PushButton
|
||||||
from Sliders import ComplexSlider
|
|
||||||
|
|
||||||
# Pathnames
|
# Pathnames
|
||||||
|
|
||||||
DEF_DB = '/usr/local/sounds/aiff' # Default directory of sounds
|
DEF_DB = '/usr/local/sounds' # Default directory of sounds
|
||||||
SOX = '/usr/local/sox' # Sound format conversion program
|
SOX = '/usr/local/sox' # Sound format conversion program
|
||||||
SFPLAY = '/usr/sbin/sfplay' # Sound playing program
|
SFPLAY = '/usr/sbin/sfplay' # Sound playing program
|
||||||
|
|
||||||
|
@ -47,7 +45,7 @@ SFPLAY = '/usr/sbin/sfplay' # Sound playing program
|
||||||
|
|
||||||
class struct(): pass # Class to define featureless structures
|
class struct(): pass # Class to define featureless structures
|
||||||
|
|
||||||
G = struct() # Holds writable global variables
|
G = struct() # oHlds writable global variables
|
||||||
|
|
||||||
|
|
||||||
# Main program
|
# Main program
|
||||||
|
@ -67,7 +65,7 @@ def main():
|
||||||
sys.stdout = sys.stderr
|
sys.stdout = sys.stderr
|
||||||
print msg
|
print msg
|
||||||
print 'usage: jukebox [-d] [-s] [-t type] [-r rate]'
|
print 'usage: jukebox [-d] [-s] [-t type] [-r rate]'
|
||||||
print ' -d debugging'
|
print ' -d debugging (-dd event debugging)'
|
||||||
print ' -s synchronous playing'
|
print ' -s synchronous playing'
|
||||||
print ' -t type file type'
|
print ' -t type file type'
|
||||||
print ' -r rate sampling rate'
|
print ' -r rate sampling rate'
|
||||||
|
@ -75,7 +73,7 @@ def main():
|
||||||
#
|
#
|
||||||
for optname, optarg in optlist:
|
for optname, optarg in optlist:
|
||||||
if optname == '-d':
|
if optname == '-d':
|
||||||
G.debug = 1
|
G.debug = G.debug + 1
|
||||||
elif optname == '-r':
|
elif optname == '-r':
|
||||||
G.rate = int(eval(optarg))
|
G.rate = int(eval(optarg))
|
||||||
elif optname == '-s':
|
elif optname == '-s':
|
||||||
|
@ -97,6 +95,10 @@ def main():
|
||||||
clearcache()
|
clearcache()
|
||||||
killchild()
|
killchild()
|
||||||
|
|
||||||
|
# Entries in Rate menu:
|
||||||
|
rates = ['default', \
|
||||||
|
'8000', '11025', '16000', '22050', '32000', '41000', '48000']
|
||||||
|
|
||||||
def maineventloop():
|
def maineventloop():
|
||||||
mouse_events = WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP
|
mouse_events = WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP
|
||||||
while G.windows:
|
while G.windows:
|
||||||
|
@ -108,6 +110,16 @@ def maineventloop():
|
||||||
checkchild()
|
checkchild()
|
||||||
if G.busy:
|
if G.busy:
|
||||||
G.cw.win.settimer(1)
|
G.cw.win.settimer(1)
|
||||||
|
elif type == WE_MENU:
|
||||||
|
menu, item = detail
|
||||||
|
if menu is G.ratemenu:
|
||||||
|
clearcache()
|
||||||
|
if item == 0:
|
||||||
|
G.rate = 0
|
||||||
|
else:
|
||||||
|
G.rate = eval(rates[item])
|
||||||
|
for i in range(len(rates)):
|
||||||
|
menu.check(i, (i == item))
|
||||||
else:
|
else:
|
||||||
G.cw.dispatch(event)
|
G.cw.dispatch(event)
|
||||||
else:
|
else:
|
||||||
|
@ -119,7 +131,7 @@ def maineventloop():
|
||||||
w.close(w)
|
w.close(w)
|
||||||
del w, event
|
del w, event
|
||||||
else:
|
else:
|
||||||
if G.debug: print type, w, detail
|
if G.debug > 1: print type, w, detail
|
||||||
|
|
||||||
def checkchild():
|
def checkchild():
|
||||||
if G.busy:
|
if G.busy:
|
||||||
|
@ -142,14 +154,24 @@ def waitchild(options):
|
||||||
def opencontrolwindow():
|
def opencontrolwindow():
|
||||||
stdwin.setdefscrollbars(0, 0)
|
stdwin.setdefscrollbars(0, 0)
|
||||||
cw = WindowParent().create('Jukebox', (0, 0))
|
cw = WindowParent().create('Jukebox', (0, 0))
|
||||||
v = VSplit().create(cw)
|
|
||||||
#
|
#
|
||||||
stop = PushButton().definetext(v, 'Stop')
|
stop = PushButton().definetext(cw, ' Stop ')
|
||||||
stop.hook = stop_hook
|
stop.hook = stop_hook
|
||||||
stop.enable(0)
|
stop.enable(0)
|
||||||
G.stop = stop
|
G.stop = stop
|
||||||
#
|
#
|
||||||
cw.realize()
|
cw.realize()
|
||||||
|
#
|
||||||
|
G.ratemenu = cw.win.menucreate('Rate')
|
||||||
|
for r in rates:
|
||||||
|
G.ratemenu.additem(r)
|
||||||
|
if G.rate == 0:
|
||||||
|
G.ratemenu.check(0, 1)
|
||||||
|
else:
|
||||||
|
for i in len(range(rates)):
|
||||||
|
if rates[i] == `G.rate`:
|
||||||
|
G.ratemenu.check(i, 1)
|
||||||
|
#
|
||||||
return cw
|
return cw
|
||||||
|
|
||||||
def stop_hook(self):
|
def stop_hook(self):
|
||||||
|
@ -264,31 +286,51 @@ cache = {}
|
||||||
|
|
||||||
def clearcache():
|
def clearcache():
|
||||||
for x in cache.keys():
|
for x in cache.keys():
|
||||||
try:
|
cmd = 'rm -f ' + cache[x]
|
||||||
sts = os.system('rm -f ' + cache[x])
|
if G.debug: print cmd
|
||||||
if sts:
|
sts = os.system(cmd)
|
||||||
print cmd
|
if sts:
|
||||||
print 'Exit status', sts
|
|
||||||
except:
|
|
||||||
print cmd
|
print cmd
|
||||||
print 'Exception?!'
|
print 'Exit status', sts
|
||||||
del cache[x]
|
del cache[x]
|
||||||
|
|
||||||
def playfile(name):
|
validrates = (8000, 11025, 16000, 22050, 32000, 44100, 48000)
|
||||||
|
|
||||||
|
def playfile(filename):
|
||||||
killchild()
|
killchild()
|
||||||
if G.mode in ('', 'au', 'aiff'):
|
import sndhdr
|
||||||
tempname = name
|
tuple = sndhdr.what(filename)
|
||||||
elif cache.has_key(name):
|
raw = 0
|
||||||
tempname = cache[name]
|
if tuple:
|
||||||
|
mode, rate = tuple[:2]
|
||||||
|
if rate == 0:
|
||||||
|
rate = G.rate
|
||||||
|
if rate == 0:
|
||||||
|
rate = 8000
|
||||||
|
else:
|
||||||
|
mode = G.mode
|
||||||
|
rate = G.rate
|
||||||
|
if G.debug: print 'mode =', mode, 'rate =', rate
|
||||||
|
if mode in ('au', 'aiff', 'wav', 'aifc', 'ul', 'ub', 'sb') and \
|
||||||
|
rate in validrates:
|
||||||
|
tempname = filename
|
||||||
|
if mode in ('ul', 'ub', 'sb'):
|
||||||
|
raw = 1
|
||||||
|
elif cache.has_key(filename):
|
||||||
|
tempname = cache[filename]
|
||||||
else:
|
else:
|
||||||
tempname = G.tempprefix + `rand.rand()` + '.aiff'
|
tempname = G.tempprefix + `rand.rand()` + '.aiff'
|
||||||
cmd = SOX
|
cmd = SOX
|
||||||
if G.mode <> '' and G.mode <> 'sox':
|
if G.debug:
|
||||||
cmd = cmd + ' -t ' + G.mode
|
cmd = cmd + ' -V'
|
||||||
cmd = cmd + ' ' + commands.mkarg(name)
|
if mode <> '':
|
||||||
|
cmd = cmd + ' -t ' + mode
|
||||||
|
cmd = cmd + ' ' + commands.mkarg(filename)
|
||||||
cmd = cmd + ' -t aiff'
|
cmd = cmd + ' -t aiff'
|
||||||
if G.rate:
|
if rate not in validrates:
|
||||||
cmd = cmd + ' -r ' + `G.rate`
|
rate = 32000
|
||||||
|
if rate:
|
||||||
|
cmd = cmd + ' -r ' + `rate`
|
||||||
cmd = cmd + ' ' + tempname
|
cmd = cmd + ' ' + tempname
|
||||||
if G.debug: print cmd
|
if G.debug: print cmd
|
||||||
sts = os.system(cmd)
|
sts = os.system(cmd)
|
||||||
|
@ -297,13 +339,11 @@ def playfile(name):
|
||||||
print 'Exit status', sts
|
print 'Exit status', sts
|
||||||
stdwin.fleep()
|
stdwin.fleep()
|
||||||
return
|
return
|
||||||
cache[name] = tempname
|
cache[filename] = tempname
|
||||||
pid = os.fork()
|
if raw:
|
||||||
if pid == 0:
|
pid = sfplayraw(tempname, tuple)
|
||||||
# Child
|
else:
|
||||||
os.exec(SFPLAY, [SFPLAY, '-r', tempname])
|
pid = sfplay(tempname, [])
|
||||||
# NOTREACHED
|
|
||||||
# Parent
|
|
||||||
if G.synchronous:
|
if G.synchronous:
|
||||||
sts = os.wait(pid, 0)
|
sts = os.wait(pid, 0)
|
||||||
else:
|
else:
|
||||||
|
@ -311,4 +351,39 @@ def playfile(name):
|
||||||
G.stop.enable(1)
|
G.stop.enable(1)
|
||||||
G.cw.win.settimer(1)
|
G.cw.win.settimer(1)
|
||||||
|
|
||||||
|
def sfplayraw(filename, tuple):
|
||||||
|
import sndhdr
|
||||||
|
args = ['-i']
|
||||||
|
type, rate, channels, frames, bits = tuple
|
||||||
|
if type == 'ul':
|
||||||
|
args.append('mulaw')
|
||||||
|
elif type == 'ub':
|
||||||
|
args = args + ['integer', '8', 'unsigned']
|
||||||
|
elif type == 'sb':
|
||||||
|
args = args + ['integer', '8', '2scomp']
|
||||||
|
else:
|
||||||
|
print 'sfplayraw: warning: unknown type in', tuple
|
||||||
|
if channels > 1:
|
||||||
|
args = args + ['channels', `channels`]
|
||||||
|
if not rate:
|
||||||
|
rate = G.rate
|
||||||
|
if rate:
|
||||||
|
args = args + ['rate', `rate`]
|
||||||
|
args.append('end')
|
||||||
|
return sfplay(filename, args)
|
||||||
|
|
||||||
|
def sfplay(filename, args):
|
||||||
|
if G.debug:
|
||||||
|
args = ['-p'] + args
|
||||||
|
args = [SFPLAY, '-r'] + args + [filename]
|
||||||
|
if G.debug: print 'sfplay:', args
|
||||||
|
pid = os.fork()
|
||||||
|
if pid == 0:
|
||||||
|
# Child
|
||||||
|
os.exec(SFPLAY, args)
|
||||||
|
# NOTREACHED
|
||||||
|
else:
|
||||||
|
# Parent
|
||||||
|
return pid
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue