readcd.py 6.04 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1 2 3 4 5 6 7
# Class interface to the CD module.

import cd, CD

Error = 'Readcd.Error'
_Stop = 'Readcd.Stop'

8
def _doatime(self, cb_type, data):
Guido van Rossum's avatar
Guido van Rossum committed
9
	if ((data[0] * 60) + data[1]) * 75 + data[2] > self.end:
10
##		print 'done with list entry',`self.listindex`
Guido van Rossum's avatar
Guido van Rossum committed
11
		raise _Stop
12
	func, arg = self.callbacks[cb_type]
Guido van Rossum's avatar
Guido van Rossum committed
13
	if func:
14
		func(arg, cb_type, data)
Guido van Rossum's avatar
Guido van Rossum committed
15

16
def _dopnum(self, cb_type, data):
Guido van Rossum's avatar
Guido van Rossum committed
17
	if data > self.end:
18
##		print 'done with list entry',`self.listindex`
Guido van Rossum's avatar
Guido van Rossum committed
19
		raise _Stop
20
	func, arg = self.callbacks[cb_type]
Guido van Rossum's avatar
Guido van Rossum committed
21
	if func:
22
		func(arg, cb_type, data)
Guido van Rossum's avatar
Guido van Rossum committed
23

24
class Readcd:
Guido van Rossum's avatar
Guido van Rossum committed
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
	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
		return self

	def eject(self):
		self.player.eject()
		self.list = []
		self.end = 0
		self.listindex = 0
		self.status = None
		self.trackinfo = None
		if self.playing:
51
##			print 'stop playing from eject'
Guido van Rossum's avatar
Guido van Rossum committed
52 53 54 55
			raise _Stop

	def pmsf2msf(self, track, min, sec, frame):
		if not self.status:
Guido van Rossum's avatar
Guido van Rossum committed
56
			self.cachestatus()
Guido van Rossum's avatar
Guido van Rossum committed
57 58
		if track < self.status[5] or track > self.status[6]:
			raise Error, 'track number out of range'
Guido van Rossum's avatar
Guido van Rossum committed
59 60
		if not self.trackinfo:
			self.cacheinfo()
Guido van Rossum's avatar
Guido van Rossum committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
		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:
Guido van Rossum's avatar
Guido van Rossum committed
80
			self.cachestatus()
Guido van Rossum's avatar
Guido van Rossum committed
81 82 83 84
		if not start:
			start = 1
		if not end:
			end = self.status[6]
85 86 87 88
		if type(end) == type(0):
			if end < self.status[5] or end > self.status[6]:
				raise Error, 'range error'
		else:
Guido van Rossum's avatar
Guido van Rossum committed
89 90 91 92 93 94 95 96
			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)
			elif l <> 3:
				raise Error, 'syntax error'
97 98
		if type(start) == type(0):
			if start < self.status[5] or start > self.status[6]:
Guido van Rossum's avatar
Guido van Rossum committed
99
				raise Error, 'range error'
100 101 102 103 104 105 106
			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:
Guido van Rossum's avatar
Guido van Rossum committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
			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)
			elif l <> 3:
				raise Error, 'syntax error'
		self.list.append((start, end))

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

122 123
	def setcallback(self, cb_type, func, arg):
		if cb_type < 0 or cb_type >= 8:
Guido van Rossum's avatar
Guido van Rossum committed
124
			raise Error, 'type out of range'
125
		self.callbacks[cb_type] = (func, arg)
Guido van Rossum's avatar
Guido van Rossum committed
126
		if self.playing:
127 128 129 130 131 132 133 134 135 136
			start, end = self.list[self.listindex]
			if type(end) == type(0):
				if cb_type <> CD.PNUM:
					self.parser.setcallback(cb_type, func, arg)
			else:
				if cb_type <> CD.ATIME:
					self.parser.setcallback(cb_type, func, arg)

	def removecallback(self, cb_type):
		if cb_type < 0 or cb_type >= 8:
Guido van Rossum's avatar
Guido van Rossum committed
137
			raise Error, 'type out of range'
138
		self.callbacks[cb_type] = (None, None)
Guido van Rossum's avatar
Guido van Rossum committed
139
		if self.playing:
140 141 142 143 144 145 146
			start, end = self.list[self.listindex]
			if type(end) == type(0):
				if cb_type <> CD.PNUM:
					self.parser.removecallback(cb_type)
			else:
				if cb_type <> CD.ATIME:
					self.parser.removecallback(cb_type)
Guido van Rossum's avatar
Guido van Rossum committed
147 148 149

	def gettrackinfo(self, *arg):
		if not self.status:
Guido van Rossum's avatar
Guido van Rossum committed
150
			self.cachestatus()
Guido van Rossum's avatar
Guido van Rossum committed
151
		if not self.trackinfo:
Guido van Rossum's avatar
Guido van Rossum committed
152
			self.cacheinfo()
Guido van Rossum's avatar
Guido van Rossum committed
153 154 155 156 157 158 159 160 161
		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

Guido van Rossum's avatar
Guido van Rossum committed
162 163 164 165 166 167 168 169 170 171
	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):
172
		self.status = self.player.getstatus()
173
		if self.status[0] == CD.NODISC:
Guido van Rossum's avatar
Guido van Rossum committed
174
			self.status = None
175
			raise Error, 'no disc in player'
Guido van Rossum's avatar
Guido van Rossum committed
176 177 178

	def getstatus(self):
		return self.player.getstatus()
Guido van Rossum's avatar
Guido van Rossum committed
179 180 181

	def play(self):
		if not self.status:
Guido van Rossum's avatar
Guido van Rossum committed
182
			self.cachestatus()
Guido van Rossum's avatar
Guido van Rossum committed
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
		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)
		while 1:
			if not self.playing:
				if self.listindex >= len(self.list):
					return
				start, end = self.list[self.listindex]
200
##				print 'starting with',`(start, end)`
201 202 203
				if type(start) == type(0):
					dummy = self.player.seektrack(start)
				else:
Guido van Rossum's avatar
Guido van Rossum committed
204 205
					min, sec, frame = start
					dummy = self.player.seek(min, sec, frame)
206 207 208 209 210 211 212 213 214
				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:
Guido van Rossum's avatar
Guido van Rossum committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
					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