home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyth_os2.zip / python-1.0.2 / Demo / sgi / dal / dal.py < prev    next >
Text File  |  1994-01-07  |  10KB  |  346 lines

  1. # Distributed Audio Library.
  2.  
  3. # This module provides an interface that is (almost) the same as that
  4. # of SGI's audio library, but which interfaces to the audio device of
  5. # the machine indicated by the $DISPLAY environment variable, rather
  6. # than the machine on which the process is running.  This means e.g.
  7. # that if you have a shell in a window on a remote machine and you run
  8. # a program that plays some sound, the sound comes out of the speaker
  9. # on the machine whose display and keyboard you are using rather than
  10. # the machine on which the shell happens to be running.
  11.  
  12. # It is possible to take an existing Python program that uses the
  13. # audio library and make a very small local change to it so that it
  14. # will be using dal instead of al, *if* $DISPLAY does not point to the
  15. # local machine.  This requires that you import dal and call
  16. # dal.takeover() *before* importing al.  For instance:
  17. #   import dal
  18. #   dal.takeover()
  19. #   import al
  20. # This should be put in the main program before importing any other
  21. # modules that might also import al.  The takeover() function does
  22. # nothing when $DISPLAY indicates the local host (in any disguise, as
  23. # long as the IP numbers match).
  24.  
  25. # It is also possible to use dal explicitly by opening a connection
  26. # and using methods of this connection:
  27. #   import dal
  28. #   conn = dal.openconn()
  29. #   port = conn.openport(...)
  30. # The openconn() function has an optional argument indicating the host
  31. # to connect to.
  32.  
  33. # A feature of openconn() and takeover() is that if $DISPLAY is not
  34. # set or points to a bad host, it does not fall back to using the
  35. # local host but raise an exception.  This means that programs run
  36. # from a non-windowed environment (e.g. a remote login from a modem)
  37. # will fail to produce sound rather than annoy the person sitting at
  38. # the machine's display.  An exception is also raised when the remote
  39. # DAL server cannot be contacted.
  40.  
  41. # It should be noted that this is only a prototype implementation.
  42. # Not all functionality is implemented, and all functions cause a
  43. # server roundtrip.  Applications that are critical to timing will
  44. # notice that remote audio operations are slower than their local
  45. # counterparts and precise synchronization with other remote I/O may
  46. # not be possible.
  47.  
  48. # CAVEAT: The server does not do any authorization checking.  Once you
  49. # start the DAL server, anyone with a DAL client can manipulate your
  50. # audio device.  You have been warned!
  51.  
  52. # XXX One possible optimization would be to open a separate TCP
  53. # connection for a port, to be used for writesamps and readsamps.  At
  54. # least for writesamps this would avoid the roundtrip.  (For readsamps
  55. # it would still require the roundtrip, but it would save some copying
  56. # time.)
  57.  
  58.  
  59. import sys
  60. sys.path.append('/ufs/guido/src/python/new/Demo/rpc')
  61. import socket
  62. import AL
  63. import al
  64. import rpc
  65. from dalxdr import *
  66.  
  67.  
  68. Error = 'dal.Error'            # Exception
  69.  
  70.  
  71. class Config:
  72.  
  73.     def __init__(self):
  74.         self.queuesize = 100000
  75.         self.width = AL.SAMPLE_16
  76.         self.channels = AL.STEREO
  77.         self.sampfmt = AL.SAMPFMT_TWOSCOMP
  78.         self.floatmax = 1.0
  79.  
  80.     def setqueuesize(self, queuesize):
  81.         self.queuesize = int(queuesize)
  82.     def getqueuesize(self):
  83.         return self.queuesize
  84.  
  85.     def setwidth(self, width):
  86.         self.width = int(width)
  87.     def getwidth(self):
  88.         return self.width
  89.  
  90.     def setchannels(self, channels):
  91.         self.channels = int(channels)
  92.     def getchannels(self):
  93.         return self.channels
  94.  
  95.     def setsampfmt(self, sampfmt):
  96.         self.sampfmt = int(sampfmt)
  97.     def getsampfmt(self):
  98.         return self.sampfmt
  99.  
  100.     def setfloatmax(self, floatmax):
  101.         self.floatmax = float(floatmax)
  102.     def getfloatmax(self):
  103.         return self.floatmax
  104.  
  105.  
  106. class Port:
  107.     def __init__(self, conn, name, config, index):
  108.         self.conn = conn
  109.         self.name = name
  110.         self.config = config
  111.         self.index = index
  112.     def closeport(self):
  113.         self.conn.call_12(self.index)
  114.         self.index = -1
  115.  
  116.     def getfd(self):
  117.         return None
  118.     fileno= getfd
  119.  
  120.     def getfilled(self):
  121.         return self.conn.call_13(self.index)
  122.     def getfillable(self):
  123.         return self.conn.call_14(self.index)
  124.  
  125.     def readsamps(self, nsamps):
  126.         return self.conn.call_15(self.index, nsamps)
  127.     def writesamps(self, buffer):
  128.         self.conn.call_16(self.index, buffer)
  129.  
  130.     def getfillpoint(self):
  131.         return self.conn.call_17(self.index)
  132.     def setfillpoint(self, fillpoint):
  133.         self.conn.call_18(self.index, fillpoint)
  134.  
  135.     def getconfig(self):
  136.         config_flat = self.conn.call_19(self.index)
  137.         queuesize, width, channels, sampfmt, floatmax = config_flat
  138.         c = al.newconfig()
  139.         c.setqueuesize(queuesize)
  140.         c.setwidth(width)
  141.         c.setchannels(channels)
  142.         c.setsampfmt(sampfmt)
  143.         c.setfloatmax(floatmax)
  144.         return c
  145.     def setconfig(self, c):
  146.         config_flat = c.getqueuesize(), c.getwidth(), \
  147.                   c.getchannels(), c.getsampfmt(), c.getfloatmax()
  148.         self.conn.call_20(self.index, config_flat)
  149.  
  150.     def getstatus(self, params):
  151.         params[:] = self.conn.call_21(self.index, params)
  152.  
  153.  
  154. class DALClient(rpc.TCPClient):
  155.  
  156.     def __init__(self, host):
  157.         rpc.TCPClient.__init__(self, host, 0x25924127, 1)
  158.     def addpackers(self):
  159.         self.packer = DALPacker()
  160.         self.unpacker = DALUnpacker('')
  161.  
  162.     def call_1(self, dev): # queryparams
  163.         return self.make_call(1, dev, \
  164.               self.packer.pack_int, \
  165.               self.unpacker.unpack_params)
  166.     def call_2(self, dev, params): # getparams
  167.         return self.make_call(2, (dev, params), \
  168.               self.packer.pack_int_params, \
  169.               self.unpacker.unpack_params)
  170.     def call_3(self, dev, params): # setparams
  171.         return self.make_call(3, (dev, params), \
  172.               self.packer.pack_int_params, \
  173.               None)
  174.     def call_4(self, dev, descr): # getname
  175.         return self.make_call(4, (dev, descr), \
  176.               self.packer.pack_int_int, \
  177.               self.unpacker.unpack_string)
  178.     def call_5(self, dev, descr): # getdefault
  179.         return self.make_call(5, (dev, descr), \
  180.               self.packer.pack_int_int, \
  181.               self.unpacker.unpack_int)
  182.     def call_6(self, dev, descr): # getminmax
  183.         return self.make_call(6 (dev, descr), \
  184.               self.packer.pack_int_int, \
  185.               self.unpacker.unpack_int_int)
  186.  
  187.     def call_11(self, name, mode, config): # openport
  188.         return self.make_call(11, (name, mode, config), \
  189.               self.packer.pack_openport, \
  190.               self.unpacker.unpack_int)
  191.     def call_12(self, i): # closeport
  192.         return self.make_call(12, i, \
  193.               self.packer.pack_int, \
  194.               None)
  195.     def call_13(self, i): # getfilled
  196.         return self.make_call(13, i, \
  197.               self.packer.pack_int, \
  198.               self.unpacker.unpack_int)
  199.     def call_14(self, i): # getfillable
  200.         return self.make_call(14, i, \
  201.               self.packer.pack_int, \
  202.               self.unpacker.unpack_int)
  203.     def call_15(self, i, n): # readsamps
  204.         return self.make_call(15, (i, n), \
  205.               self.packer.pack_readsamps, \
  206.               self.unpacker.unpack_string)
  207.     def call_16(self, i, buffer): # writesamps
  208.         return self.make_call(16, (i, buffer), \
  209.               self.packer.pack_writesamps, \
  210.               None)
  211.     def call_17(self, i): # getfillpoint
  212.         return self.make_call(17, i, \
  213.               self.packer.pack_int, \
  214.               self.unpacker.unpack_int)
  215.     def call_18(self, i, fillpoint): # setfillpoint
  216.         return self.make_call(18, (i, fillpoint), \
  217.               self.packer.pack_int_int, \
  218.               None)
  219.     def call_19(self, i): # getconfig
  220.         return self.make_call(19, i, \
  221.               self.packer.pack_int, \
  222.               self.unpacker.unpack_config)
  223.     def call_20(self, i, config_flat): # setconfig
  224.         return self.make_call(20, (i, config_flat), \
  225.               self.packer.pack_setconfig, \
  226.               None)
  227.     def call_21(self, i, params): # getstatus
  228.         return self.make_call(21, (i, params), \
  229.               self.packer.pack_int_params, \
  230.               self.unpacker.unpack_params)
  231.  
  232.     def newconfig(self):
  233.         return Config()
  234.  
  235.     def queryparams(self, dev):
  236.         return self.call_1(dev)
  237.     def getparams(self, dev, params):
  238.         params[:] = self.call_2(dev, params)
  239.     def setparams(self, dev, params):
  240.         self.call_3(dev, params)
  241.     def getname(self, dev, descr):
  242.         return self.call_4(dev, descr)
  243.     def getdefault(self, dev, descr):
  244.         return self.call_5(dev, descr)
  245.     def getminmax(self, dev, descr):
  246.         return self.call_6(dev, descr)
  247.  
  248.     def openport(self, name, mode, *args):
  249.         if len(args) > 1: raise TypeError, 'too many args'
  250.         if args:
  251.             c = args[0]
  252.         else:
  253.             c = self.newconfig()
  254.         config_flat = c.getqueuesize(), c.getwidth(), \
  255.                   c.getchannels(), c.getsampfmt(), c.getfloatmax()
  256.         index = self.call_11(name, mode, config_flat)
  257.         if index < 0:
  258.             raise Error, 'openport failed'
  259.         return Port(self, name, c, index)
  260.  
  261.  
  262. def takeover():
  263.     import os
  264.     import sys
  265.     import string
  266.     if not sys.modules.has_key('_local_al'):
  267.         sys.modules['_local_al'] = sys.modules['al']
  268.     host = defaulthost()
  269.     if host:
  270.         sys.modules['al'] = openconn(host)
  271.  
  272.  
  273. def openconn(*args):
  274.     if len(args) > 1: raise TypeError, 'too many args'
  275.     if args:
  276.         host = args[0]
  277.     else:
  278.         host = defaulthost()
  279.     return DALClient(host)
  280.  
  281.  
  282. def defaulthost():
  283.     import os
  284.     import string
  285.     if not os.environ.has_key('DISPLAY'):
  286.         raise Error, '$DISPLAY not set'
  287.     display = os.environ['DISPLAY']
  288.     words = string.splitfields(display, ':')
  289.     if len(words) <> 2:
  290.         raise Error, 'bad $DISPLAY format'
  291.     [host, number] = words
  292.     if not host or host == 'unix':
  293.         return ''        # Implied local display
  294.     # Compare host IP addresses, not hostname, because of aliases
  295.     try:
  296.         iphost = socket.gethostbyname(host)
  297.     except socket.error:
  298.         raise Error, 'bad host in $DISPLAY'
  299.     iplocalhost = socket.gethostbyname(socket.gethostname())
  300.     if iphost == iplocalhost:
  301.         return ''        # Explicit local display
  302.     return iphost
  303.  
  304.  
  305. def test():
  306.     import sys
  307.     import os
  308.     import time
  309.     if sys.argv[1:]: file = sys.argv[1]
  310.     else: file = '/usr/local/sounds/aiff/1999_intro.aiff'
  311. ##    else: file = '/usr/local/sounds/aiff/Ah_Ha!.aiff'
  312.     f = open(file, 'r')
  313.     f.seek(64) # Skip header bytes
  314.     conn = openconn()
  315.     c = conn.newconfig()
  316.     c.setqueuesize(100000)
  317. ##    c.setchannels(AL.MONO)
  318.     p = conn.openport('test', 'r', c)
  319.     try:
  320.         buffer = p.readsamps(1000)
  321.     finally:
  322.         p.closeport()
  323.     p = conn.openport('test', 'w', c)
  324.     p.writesamps(buffer)
  325.     try:
  326.         while 1:
  327.             buffer = f.read(50000)
  328.             if not buffer:
  329.                 break
  330.             p.writesamps(buffer)
  331.         while p.getfilled() > 0:
  332.             time.sleep(0.1)
  333.     finally:
  334.         p.closeport()
  335.  
  336.  
  337. def test1():
  338.     import time
  339.     conn = openconn()
  340. ##    p = conn.openport('test1', 'r', c)
  341.     t0 = time.time()
  342.     for i in range(100):
  343.         conn.call_0()
  344.     t1 = time.time()
  345.     print round(t1-t0, 3), 'sec.'
  346.