"""Classes for manipulating audio devices (currently only for Sun and SGI)"""

class error(Exception):
	pass

class Play_Audio_sgi:
	# Private instance variables
## 	if 0: access frameratelist, nchannelslist, sampwidthlist, oldparams, \
## 		  params, config, inited_outrate, inited_width, \
## 		  inited_nchannels, port, converter, classinited: private

	classinited = 0
	frameratelist = nchannelslist = sampwidthlist = None

	def initclass(self):
		import AL
		self.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),
			  ]
		self.nchannelslist = [
			  (1, AL.MONO),
			  (2, AL.STEREO),
			  (4, AL.QUADRO),
			  ]
		self.sampwidthlist = [
			  (1, AL.SAMPLE_8),
			  (2, AL.SAMPLE_16),
			  (3, AL.SAMPLE_24),
			  ]
		self.classinited = 1

	def __init__(self):
		import al, AL
		if not self.classinited:
			self.initclass()
		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
			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
			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:
				import AL
				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, 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
## 	if 0: access *: private

	def ulaw2lin(self, data):
		import audioop
		return audioop.ulaw2lin(data, 2)

class Play_Audio_sun:
## 	if 0: 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, 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 = SUNAUDIODEV.ENCODING_ULAW
				# XXX Hack, hack -- leave defaults
			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():
	# Dynamically try to import and use a platform specific module.
	try:
		import al
	except ImportError:
		try:
			import sunaudiodev
			return Play_Audio_sun()
		except ImportError:
			try:
				import Audio_mac
			except ImportError:
				raise error, 'no audio device'
			else:
				return Audio_mac.Play_Audio_mac()
	else:
		return Play_Audio_sgi()

def test(fn = None):
	import sys
	if sys.argv[1:]:
		fn = sys.argv[1]
	else:
		fn = 'f:just samples:just.aif'
	import aifc
	af = aifc.open(fn, 'r')
	print fn, af.getparams()
	p = AudioDev()
	p.setoutrate(af.getframerate())
	p.setsampwidth(af.getsampwidth())
	p.setnchannels(af.getnchannels())
	BUFSIZ = af.getframerate()/af.getsampwidth()/af.getnchannels()
	while 1:
		data = af.readframes(BUFSIZ)
		if not data: break
		print len(data)
		p.writeframes(data)
	p.wait()

if __name__ == '__main__':
	test()
