Interface to audio hardware for SGI and Sun.
diff --git a/Lib/audiodev.py b/Lib/audiodev.py
new file mode 100644
index 0000000..d0dcfed
--- /dev/null
+++ b/Lib/audiodev.py
@@ -0,0 +1,205 @@
+import AL, SUNAUDIODEV
+
+error = 'audiodev.error'
+
+class Play_Audio_sgi:
+	# Private instance variables
+	access frameratelist, nchannelslist, sampwidthlist, oldparams, \
+		  params, config, inited_outrate, inited_width, \
+		  inited_nchannels, port, converter: private
+
+	frameratelist = [(48000, AL.RATE_48000),
+			 (44100, AL.RATE_44100),
+			 (32000, AL.RATE_32000),
+			 (22050, AL.RATE_22050),
+			 (16000, AL.RATE_16000),
+			 (11025, AL.RATE_11025),
+			 ( 8000,  AL.RATE_8000)]
+	nchannelslist = [(1, AL.MONO),
+			 (2, AL.STEREO)]
+	sampwidthlist = [(1, AL.SAMPLE_8),
+			 (2, AL.SAMPLE_16),
+			 (3, AL.SAMPLE_24)]
+
+	def __init__(self):
+		import al
+		self.oldparams = []
+		self.params = [AL.OUTPUT_RATE, 0]
+		self.config = al.newconfig()
+		self.inited_outrate = 0
+		self.inited_width = 0
+		self.inited_nchannels = 0
+		self.converter = None
+		self.port = None
+		return
+
+	def __del__(self):
+		if self.port:
+			self.stop()
+		if self.oldparams:
+			import al
+			al.setparams(AL.DEFAULT_DEVICE, self.oldparams)
+			self.oldparams = []
+
+	def wait(self):
+		if not self.port:
+			return
+		import time
+		while self.port.getfilled() > 0:
+			time.sleep(0.1)
+		self.stop()
+
+	def stop(self):
+		if self.port:
+			self.port.closeport()
+			self.port = None
+		if self.oldparams:
+			import al
+			al.setparams(AL.DEFAULT_DEVICE, self.oldparams)
+			self.oldparams = []
+
+	def setoutrate(self, rate):
+		for (raw, cooked) in self.frameratelist:
+			if rate == raw:
+				self.params[1] = cooked
+				self.inited_outrate = 1
+				break
+		else:
+			raise error, 'bad output rate'
+
+	def setsampwidth(self, width):
+		for (raw, cooked) in self.sampwidthlist:
+			if width == raw:
+				self.config.setwidth(cooked)
+				self.inited_width = 1
+				break
+		else:
+			if width == 0:
+				self.inited_width = 0
+				self.config.setwidth(AL.SAMPLE_16)
+				self.converter = self.ulaw2lin
+			else:
+				raise error, 'bad sample width'
+
+	def setnchannels(self, nchannels):
+		for (raw, cooked) in self.nchannelslist:
+			if nchannels == raw:
+				self.config.setchannels(cooked)
+				self.inited_nchannels = 1
+				break
+		else:
+			raise error, 'bad # of channels'
+
+	def writeframes(self, data):
+		if not (self.inited_outrate and self.inited_nchannels):
+			raise error, 'params not specified'
+		if not self.port:
+			import al
+			self.port = al.openport('Python', 'w', self.config)
+			self.oldparams = self.params[:]
+			al.getparams(AL.DEFAULT_DEVICE, self.oldparams)
+			al.setparams(AL.DEFAULT_DEVICE, self.params)
+		if self.converter:
+			data = self.converter(data)
+		self.port.writesamps(data)
+
+	def getfilled(self):
+		if self.port:
+			return self.port.getfilled()
+		else:
+			return 0
+
+	def getfillable(self):
+		if self.port:
+			return self.port.getfillable()
+		else:
+			return self.config.getqueuesize()
+
+	# private methods
+	access *: private
+
+	def ulaw2lin(self, data):
+		import audioop
+		return audioop.ulaw2lin(data, 2)
+
+class Play_Audio_sun:
+	access outrate, sampwidth, nchannels, inited_outrate, inited_width, \
+		  inited_nchannels, converter: private
+
+	def __init__(self):
+		self.outrate = 0
+		self.sampwidth = 0
+		self.nchannels = 0
+		self.inited_outrate = 0
+		self.inited_width = 0
+		self.inited_nchannels = 0
+		self.converter = None
+		self.port = None
+		return
+
+	def __del__(self):
+		self.stop()
+
+	def setoutrate(self, rate):
+		self.outrate = rate
+		self.inited_outrate = 1
+
+	def setsampwidth(self, width):
+		self.sampwidth = width
+		self.inited_width = 1
+
+	def setnchannels(self, nchannels):
+		self.nchannels = nchannels
+		self.inited_nchannels = 1
+
+	def writeframes(self, data):
+		if not (self.inited_outrate and self.inited_width and self.inited_nchannels):
+			raise error, 'params not specified'
+		if not self.port:
+			import sunaudiodev
+			self.port = sunaudiodev.open('w')
+			info = self.port.getinfo()
+			info.o_sample_rate = self.outrate
+			info.o_channels = self.nchannels
+			if self.sampwidth == 0:
+				info.o_precision = 8
+				self.o_encoding = ENCODING_ULAW
+			else:
+				info.o_precision = 8 * self.sampwidth
+				info.o_encoding = SUNAUDIODEV.ENCODING_LINEAR
+			self.port.setinfo(info)
+		if self.converter:
+			data = self.converter(data)
+		self.port.write(data)
+
+	def wait(self):
+		if not self.port:
+			return
+		self.port.drain()
+		self.stop()
+
+	def stop(self):
+		if self.port:
+			self.port.flush()
+			self.port.close()
+			self.port = None
+
+	def getfilled(self):
+		if self.port:
+			return self.port.obufcount()
+		else:
+			return 0
+
+	def getfillable(self):
+		return BUFFERSIZE - self.getfilled()
+
+def AudioDev():
+	try:
+		import al
+		return Play_Audio_sgi()
+	except ImportError:
+		try:
+			import sunaudiodev
+			return Play_Audio_sun()
+		except ImportError:
+			raise error, 'no audio device'