readcd.py 6.16 KB
Newer Older
1 2 3 4
# Class interface to the CD module.

import cd, CD

5 6 7 8
class Error(Exception):
	pass
class _Stop(Exception):
	pass
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

def _doatime(self, cb_type, data):
	if ((data[0] * 60) + data[1]) * 75 + data[2] > self.end:
##		print 'done with list entry',`self.listindex`
		raise _Stop
	func, arg = self.callbacks[cb_type]
	if func:
		func(arg, cb_type, data)

def _dopnum(self, cb_type, data):
	if data > self.end:
##		print 'done with list entry',`self.listindex`
		raise _Stop
	func, arg = self.callbacks[cb_type]
	if func:
		func(arg, cb_type, data)

class Readcd:
	def __init__(self, *arg):
		if len(arg) == 0:
			self.player = cd.open()
		elif len(arg) == 1:
			self.player = cd.open(arg[0])
		elif len(arg) == 2:
			self.player = cd.open(arg[0], arg[1])
		else:
			raise Error, 'bad __init__ call'
		self.list = []
		self.callbacks = [(None, None)] * 8
		self.parser = cd.createparser()
		self.playing = 0
		self.end = 0
		self.status = None
		self.trackinfo = None

	def eject(self):
		self.player.eject()
		self.list = []
		self.end = 0
		self.listindex = 0
		self.status = None
		self.trackinfo = None
		if self.playing:
##			print 'stop playing from eject'
			raise _Stop

	def pmsf2msf(self, track, min, sec, frame):
		if not self.status:
			self.cachestatus()
		if track < self.status[5] or track > self.status[6]:
			raise Error, 'track number out of range'
		if not self.trackinfo:
			self.cacheinfo()
		start, total = self.trackinfo[track]
		start = ((start[0] * 60) + start[1]) * 75 + start[2]
		total = ((total[0] * 60) + total[1]) * 75 + total[2]
		block = ((min * 60) + sec) * 75 + frame
		if block > total:
			raise Error, 'out of range'
		block = start + block
		min, block = divmod(block, 75*60)
		sec, frame = divmod(block, 75)
		return min, sec, frame

	def reset(self):
		self.list = []

	def appendtrack(self, track):
		self.appendstretch(track, track)
				
	def appendstretch(self, start, end):
		if not self.status:
			self.cachestatus()
		if not start:
			start = 1
		if not end:
			end = self.status[6]
		if type(end) == type(0):
			if end < self.status[5] or end > self.status[6]:
				raise Error, 'range error'
		else:
			l = len(end)
			if l == 4:
				prog, min, sec, frame = end
				if prog < self.status[5] or prog > self.status[6]:
					raise Error, 'range error'
				end = self.pmsf2msf(prog, min, sec, frame)
96
			elif l != 3:
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
				raise Error, 'syntax error'
		if type(start) == type(0):
			if start < self.status[5] or start > self.status[6]:
				raise Error, 'range error'
			if len(self.list) > 0:
				s, e = self.list[-1]
				if type(e) == type(0):
					if start == e+1:
						start = s
						del self.list[-1]
		else:
			l = len(start)
			if l == 4:
				prog, min, sec, frame = start
				if prog < self.status[5] or prog > self.status[6]:
					raise Error, 'range error'
				start = self.pmsf2msf(prog, min, sec, frame)
114
			elif l != 3:
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
				raise Error, 'syntax error'
		self.list.append((start, end))

	def settracks(self, list):
		self.list = []
		for track in list:
			self.appendtrack(track)

	def setcallback(self, cb_type, func, arg):
		if cb_type < 0 or cb_type >= 8:
			raise Error, 'type out of range'
		self.callbacks[cb_type] = (func, arg)
		if self.playing:
			start, end = self.list[self.listindex]
			if type(end) == type(0):
130
				if cb_type != CD.PNUM:
131 132
					self.parser.setcallback(cb_type, func, arg)
			else:
133
				if cb_type != CD.ATIME:
134 135 136 137 138 139 140 141 142
					self.parser.setcallback(cb_type, func, arg)

	def removecallback(self, cb_type):
		if cb_type < 0 or cb_type >= 8:
			raise Error, 'type out of range'
		self.callbacks[cb_type] = (None, None)
		if self.playing:
			start, end = self.list[self.listindex]
			if type(end) == type(0):
143
				if cb_type != CD.PNUM:
144 145
					self.parser.removecallback(cb_type)
			else:
146
				if cb_type != CD.ATIME:
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
					self.parser.removecallback(cb_type)

	def gettrackinfo(self, *arg):
		if not self.status:
			self.cachestatus()
		if not self.trackinfo:
			self.cacheinfo()
		if len(arg) == 0:
			return self.trackinfo[self.status[5]:self.status[6]+1]
		result = []
		for i in arg:
			if i < self.status[5] or i > self.status[6]:
				raise Error, 'range error'
			result.append(self.trackinfo[i])
		return result

	def cacheinfo(self):
		if not self.status:
			self.cachestatus()
		self.trackinfo = []
		for i in range(self.status[5]):
			self.trackinfo.append(None)
		for i in range(self.status[5], self.status[6]+1):
			self.trackinfo.append(self.player.gettrackinfo(i))

	def cachestatus(self):
		self.status = self.player.getstatus()
		if self.status[0] == CD.NODISC:
			self.status = None
			raise Error, 'no disc in player'

	def getstatus(self):
		return self.player.getstatus()

	def play(self):
		if not self.status:
			self.cachestatus()
		size = self.player.bestreadsize()
		self.listindex = 0
		self.playing = 0
		for i in range(8):
			func, arg = self.callbacks[i]
			if func:
				self.parser.setcallback(i, func, arg)
			else:
				self.parser.removecallback(i)
		if len(self.list) == 0:
			for i in range(self.status[5], self.status[6]+1):
				self.appendtrack(i)
		try:
			while 1:
				if not self.playing:
					if self.listindex >= len(self.list):
						return
					start, end = self.list[self.listindex]
					if type(start) == type(0):
						dummy = self.player.seektrack(
							start)
					else:
						min, sec, frame = start
						dummy = self.player.seek(
							min, sec, frame)
					if type(end) == type(0):
						self.parser.setcallback(
							CD.PNUM, _dopnum, self)
						self.end = end
						func, arg = \
						      self.callbacks[CD.ATIME]
						if func:
							self.parser.setcallback(CD.ATIME, func, arg)
						else:
							self.parser.removecallback(CD.ATIME)
					else:
						min, sec, frame = end
						self.parser.setcallback(
							CD.ATIME, _doatime,
							self)
						self.end = (min * 60 + sec) * \
							   75 + frame
						func, arg = \
						      self.callbacks[CD.PNUM]
						if func:
							self.parser.setcallback(CD.PNUM, func, arg)
						else:
							self.parser.removecallback(CD.PNUM)
					self.playing = 1
				data = self.player.readda(size)
				if data == '':
					self.playing = 0
					self.listindex = self.listindex + 1
					continue
				try:
					self.parser.parseframe(data)
				except _Stop:
					self.playing = 0
					self.listindex = self.listindex + 1
		finally:
			self.playing = 0