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, classinited: private

	classinited = 0
	frameratelist = nchannelslist = sampwidthlist = None

	def initclass(self):
		import AL
		Play_Audio_sgi.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),
			  ]
		Play_Audio_sgi.nchannelslist = [
			  (1, AL.MONO),
			  (2, AL.STEREO),
			  ]
		Play_Audio_sgi.sampwidthlist = [
			  (1, AL.SAMPLE_8),
			  (2, AL.SAMPLE_16),
			  (3, AL.SAMPLE_24),
			  ]
		Play_Audio_sgi.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
	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, 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:
			try:
				import Audio_mac
				return Audio_mac.Play_Audio_mac()
			except ImportError:
				raise error, 'no audio device'

def test(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()
