blob: e000d35047cf28c0791cb4a6d6862819b57271c4 [file] [log] [blame]
Guido van Rossum1ce7c6f1997-01-15 19:19:19 +00001# Class interface to the CD module.
2
3import cd, CD
4
Fred Drakedef00382000-08-18 14:59:33 +00005class Error(Exception):
6 pass
7class _Stop(Exception):
8 pass
Guido van Rossum1ce7c6f1997-01-15 19:19:19 +00009
10def _doatime(self, cb_type, data):
11 if ((data[0] * 60) + data[1]) * 75 + data[2] > self.end:
12## print 'done with list entry',`self.listindex`
13 raise _Stop
14 func, arg = self.callbacks[cb_type]
15 if func:
16 func(arg, cb_type, data)
17
18def _dopnum(self, cb_type, data):
19 if data > self.end:
20## print 'done with list entry',`self.listindex`
21 raise _Stop
22 func, arg = self.callbacks[cb_type]
23 if func:
24 func(arg, cb_type, data)
25
26class Readcd:
27 def __init__(self, *arg):
28 if len(arg) == 0:
29 self.player = cd.open()
30 elif len(arg) == 1:
31 self.player = cd.open(arg[0])
32 elif len(arg) == 2:
33 self.player = cd.open(arg[0], arg[1])
34 else:
35 raise Error, 'bad __init__ call'
36 self.list = []
37 self.callbacks = [(None, None)] * 8
38 self.parser = cd.createparser()
39 self.playing = 0
40 self.end = 0
41 self.status = None
42 self.trackinfo = None
43
44 def eject(self):
45 self.player.eject()
46 self.list = []
47 self.end = 0
48 self.listindex = 0
49 self.status = None
50 self.trackinfo = None
51 if self.playing:
52## print 'stop playing from eject'
53 raise _Stop
54
55 def pmsf2msf(self, track, min, sec, frame):
56 if not self.status:
57 self.cachestatus()
58 if track < self.status[5] or track > self.status[6]:
59 raise Error, 'track number out of range'
60 if not self.trackinfo:
61 self.cacheinfo()
62 start, total = self.trackinfo[track]
63 start = ((start[0] * 60) + start[1]) * 75 + start[2]
64 total = ((total[0] * 60) + total[1]) * 75 + total[2]
65 block = ((min * 60) + sec) * 75 + frame
66 if block > total:
67 raise Error, 'out of range'
68 block = start + block
69 min, block = divmod(block, 75*60)
70 sec, frame = divmod(block, 75)
71 return min, sec, frame
72
73 def reset(self):
74 self.list = []
75
76 def appendtrack(self, track):
77 self.appendstretch(track, track)
78
79 def appendstretch(self, start, end):
80 if not self.status:
81 self.cachestatus()
82 if not start:
83 start = 1
84 if not end:
85 end = self.status[6]
86 if type(end) == type(0):
87 if end < self.status[5] or end > self.status[6]:
88 raise Error, 'range error'
89 else:
90 l = len(end)
91 if l == 4:
92 prog, min, sec, frame = end
93 if prog < self.status[5] or prog > self.status[6]:
94 raise Error, 'range error'
95 end = self.pmsf2msf(prog, min, sec, frame)
Fred Drake132dce22000-12-12 23:11:42 +000096 elif l != 3:
Guido van Rossum1ce7c6f1997-01-15 19:19:19 +000097 raise Error, 'syntax error'
98 if type(start) == type(0):
99 if start < self.status[5] or start > self.status[6]:
100 raise Error, 'range error'
101 if len(self.list) > 0:
102 s, e = self.list[-1]
103 if type(e) == type(0):
104 if start == e+1:
105 start = s
106 del self.list[-1]
107 else:
108 l = len(start)
109 if l == 4:
110 prog, min, sec, frame = start
111 if prog < self.status[5] or prog > self.status[6]:
112 raise Error, 'range error'
113 start = self.pmsf2msf(prog, min, sec, frame)
Fred Drake132dce22000-12-12 23:11:42 +0000114 elif l != 3:
Guido van Rossum1ce7c6f1997-01-15 19:19:19 +0000115 raise Error, 'syntax error'
116 self.list.append((start, end))
117
118 def settracks(self, list):
119 self.list = []
120 for track in list:
121 self.appendtrack(track)
122
123 def setcallback(self, cb_type, func, arg):
124 if cb_type < 0 or cb_type >= 8:
125 raise Error, 'type out of range'
126 self.callbacks[cb_type] = (func, arg)
127 if self.playing:
128 start, end = self.list[self.listindex]
129 if type(end) == type(0):
Fred Drake132dce22000-12-12 23:11:42 +0000130 if cb_type != CD.PNUM:
Guido van Rossum1ce7c6f1997-01-15 19:19:19 +0000131 self.parser.setcallback(cb_type, func, arg)
132 else:
Fred Drake132dce22000-12-12 23:11:42 +0000133 if cb_type != CD.ATIME:
Guido van Rossum1ce7c6f1997-01-15 19:19:19 +0000134 self.parser.setcallback(cb_type, func, arg)
135
136 def removecallback(self, cb_type):
137 if cb_type < 0 or cb_type >= 8:
138 raise Error, 'type out of range'
139 self.callbacks[cb_type] = (None, None)
140 if self.playing:
141 start, end = self.list[self.listindex]
142 if type(end) == type(0):
Fred Drake132dce22000-12-12 23:11:42 +0000143 if cb_type != CD.PNUM:
Guido van Rossum1ce7c6f1997-01-15 19:19:19 +0000144 self.parser.removecallback(cb_type)
145 else:
Fred Drake132dce22000-12-12 23:11:42 +0000146 if cb_type != CD.ATIME:
Guido van Rossum1ce7c6f1997-01-15 19:19:19 +0000147 self.parser.removecallback(cb_type)
148
149 def gettrackinfo(self, *arg):
150 if not self.status:
151 self.cachestatus()
152 if not self.trackinfo:
153 self.cacheinfo()
154 if len(arg) == 0:
155 return self.trackinfo[self.status[5]:self.status[6]+1]
156 result = []
157 for i in arg:
158 if i < self.status[5] or i > self.status[6]:
159 raise Error, 'range error'
160 result.append(self.trackinfo[i])
161 return result
162
163 def cacheinfo(self):
164 if not self.status:
165 self.cachestatus()
166 self.trackinfo = []
167 for i in range(self.status[5]):
168 self.trackinfo.append(None)
169 for i in range(self.status[5], self.status[6]+1):
170 self.trackinfo.append(self.player.gettrackinfo(i))
171
172 def cachestatus(self):
173 self.status = self.player.getstatus()
174 if self.status[0] == CD.NODISC:
175 self.status = None
176 raise Error, 'no disc in player'
177
178 def getstatus(self):
179 return self.player.getstatus()
180
181 def play(self):
182 if not self.status:
183 self.cachestatus()
184 size = self.player.bestreadsize()
185 self.listindex = 0
186 self.playing = 0
187 for i in range(8):
188 func, arg = self.callbacks[i]
189 if func:
190 self.parser.setcallback(i, func, arg)
191 else:
192 self.parser.removecallback(i)
193 if len(self.list) == 0:
194 for i in range(self.status[5], self.status[6]+1):
195 self.appendtrack(i)
196 try:
197 while 1:
198 if not self.playing:
199 if self.listindex >= len(self.list):
200 return
201 start, end = self.list[self.listindex]
202 if type(start) == type(0):
203 dummy = self.player.seektrack(
204 start)
205 else:
206 min, sec, frame = start
207 dummy = self.player.seek(
208 min, sec, frame)
209 if type(end) == type(0):
210 self.parser.setcallback(
211 CD.PNUM, _dopnum, self)
212 self.end = end
213 func, arg = \
214 self.callbacks[CD.ATIME]
215 if func:
216 self.parser.setcallback(CD.ATIME, func, arg)
217 else:
218 self.parser.removecallback(CD.ATIME)
219 else:
220 min, sec, frame = end
221 self.parser.setcallback(
222 CD.ATIME, _doatime,
223 self)
224 self.end = (min * 60 + sec) * \
225 75 + frame
226 func, arg = \
227 self.callbacks[CD.PNUM]
228 if func:
229 self.parser.setcallback(CD.PNUM, func, arg)
230 else:
231 self.parser.removecallback(CD.PNUM)
232 self.playing = 1
233 data = self.player.readda(size)
234 if data == '':
235 self.playing = 0
236 self.listindex = self.listindex + 1
237 continue
238 try:
239 self.parser.parseframe(data)
240 except _Stop:
241 self.playing = 0
242 self.listindex = self.listindex + 1
243 finally:
244 self.playing = 0