1 /* OpenCP Module Player
2 * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3 *
4 * Interface routines for Audio CD player
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * revision history: (please note changes here)
21 * -nb980510 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
22 * -first release
23 * -ss040907 Stian Skjelstad <stian@nixia.no>
24 * -removed cdReadDir
25 * -Linux related changes
26 */
27
28 #include "config.h"
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <linux/cdrom.h>
34 #include "types.h"
35 #include "cdaudio.h"
36 #include "boot/plinkman.h"
37 #include "cpiface/cpiface.h"
38 #include "dev/deviplay.h"
39 #include "dev/devisamp.h"
40 #include "filesel/dirdb.h"
41 #include "filesel/filesystem.h"
42 #include "filesel/mdb.h"
43 #include "filesel/pfilesel.h"
44 #include "stuff/compat.h"
45 #include "stuff/err.h"
46 #include "stuff/poutput.h"
47 #include "stuff/sets.h"
48
49 static unsigned long cdpTrackStarts[CDROM_LEADOUT+1];
50 static unsigned char cdpFirstTrack;
51 static unsigned char cdpPlayMode; /* 1 = disk, 0 = track */
52 static unsigned char cdpTrackNum; /* current track, calculated in GStrings */
53 static int cdpViewSectors; /* ??? view-option */
54 static unsigned long basesec; /* current start... usually a cdpTrack[n] value */
55 static unsigned long length; /* and the length of it */
56 static signed long newpos; /* skip to */
57 static unsigned char setnewpos; /* and the fact we should skip */
58 static char vdev[8];
59
60 static int16_t speed;
61 static char finespeed=8;
62 static time_t pausefadestart;
63 static uint8_t pausefaderelspeed;
64 static int8_t pausefadedirect;
65 static int cdrom_fd;
66
startpausefade(void)67 static void startpausefade(void)
68 {
69 if (pausefadedirect)
70 {
71 if (pausefadedirect<0)
72 plPause=1;
73 pausefadestart=2*dos_clock()-DOS_CLK_TCK-pausefadestart;
74 } else
75 pausefadestart=dos_clock();
76
77 if (plPause)
78 {
79 plChanChanged=1;
80 plPause=0;
81 cdRestart(cdrom_fd);
82 pausefadedirect=1;
83 } else
84 pausefadedirect=-1;
85 }
86
normalize(void)87 static void normalize(void)
88 {
89 mcpNormalize(0);
90 speed=set.speed;
91 cdSetSpeed(speed);
92 }
93
dopausefade(void)94 static void dopausefade(void)
95 {
96 int16_t i;
97 if (pausefadedirect>0)
98 {
99 i=(dos_clock()-pausefadestart)*64/DOS_CLK_TCK;
100 if (i<0)
101 i=0;
102 if (i>=64)
103 {
104 i=64;
105 pausefadedirect=0;
106 }
107 } else {
108 i=64-(dos_clock()-pausefadestart)*64/DOS_CLK_TCK;
109 if (i>=64)
110 i=64;
111 if (i<=0)
112 {
113 i=0;
114 pausefadedirect=0;
115 plPause=1;
116 cdPause(cdrom_fd);
117 plChanChanged=1;
118 cdSetSpeed(speed);
119 return;
120 }
121 }
122 pausefaderelspeed=i;
123 cdSetSpeed(speed*i/64);
124 }
gettimestr(unsigned long s,char * time)125 static char *gettimestr(unsigned long s, char *time)
126 {
127 unsigned char csec, sec, min;
128 csec=(s%75)*4/3;
129 time[8]=0;
130 time[7]='0'+csec%10;
131 time[6]='0'+csec/10;
132 sec=(s/75)%60;
133 time[5]=':';
134 time[4]='0'+sec%10;
135 time[3]='0'+sec/10;
136 min=s/(75*60);
137 time[2]=':';
138 time[1]='0'+min%10;
139 time[0]='0'+min/10;
140 return time;
141 }
142
cdaDrawGStrings(uint16_t (* buf)[CONSOLE_MAX_X])143 static void cdaDrawGStrings(uint16_t (*buf)[CONSOLE_MAX_X])
144 {
145 int i;
146 char timestr[9];
147
148 struct cdStat stat;
149
150 cdGetStatus(cdrom_fd, &stat);
151
152
153 memset(buf[0]+80, 0, (plScrWidth-80)*sizeof(uint16_t));
154 memset(buf[1]+80, 0, (plScrWidth-80)*sizeof(uint16_t));
155 memset(buf[2]+80, 0, (plScrWidth-80)*sizeof(uint16_t));
156
157 writestring(buf[0], 0, 0x09, " mode: .......... ", 20);
158 writestring(buf[0], 8, 0x0F, "cd-audio", 10);
159 for (i=1; i<=cdpTrackNum; i++)
160 if (stat.position<cdpTrackStarts[i])
161 break;
162
163 writestring(buf[0], 20, 0x09, "playmode: ..... status: .......", plScrWidth-20);
164 writestring(buf[0], 30, 0x0F, cdpPlayMode?"disk ":"track", 5);
165 writestring(buf[0], 45, 0x0F, (stat.error)?" error":(stat.paused)?" paused":"playing", 7);
166 writestring(buf[0], 52, 0x0F, " speed: ...%", 28);
167 _writenum(buf[0], 76, 0x0F, stat.speed*100/256, 10, 3);
168
169 writestring(buf[1], 0, 0x09, "drive: ....... start: :..:.. pos: :..:.. length: :..:.. size: ...... kb", plScrWidth);
170 writestring(buf[1], 7, 0x0F, vdev, 7); /* VERY TODO.. can we fit more data on this line??? */
171 if (cdpViewSectors)
172 {
173 writenum(buf[1], 22, 0x0F, cdpTrackStarts[0], 10, 8, 0);
174 writenum(buf[1], 37, 0x0F, stat.position-cdpTrackStarts[0], 10, 8, 0);
175 writenum(buf[1], 55, 0x0F, cdpTrackStarts[cdpTrackNum+1]-cdpTrackStarts[0], 10, 8, 0);
176 } else {
177 writestring(buf[1], 22, 0x0F, gettimestr(cdpTrackStarts[0]+150, timestr), 8);
178 writestring(buf[1], 37, 0x0F, gettimestr(stat.position-cdpTrackStarts[0], timestr), 8);
179 writestring(buf[1], 55, 0x0F, gettimestr(cdpTrackStarts[cdpTrackNum+1]-cdpTrackStarts[0], timestr), 8);
180 }
181 _writenum(buf[1], 71, 0x0F, (cdpTrackStarts[cdpTrackNum+1]-cdpTrackStarts[0])*147/64, 10, 6);
182
183 writestring(buf[2], 0, 0x09, "track: .. start: :..:.. pos: :..:.. length: :..:.. size: ...... kb", plScrWidth);
184 _writenum(buf[2], 7, 0x0F, i-1+cdpFirstTrack, 10, 2);
185 if (cdpViewSectors)
186 {
187 writenum(buf[2], 22, 0x0F, cdpTrackStarts[i-1]+150, 10, 8, 0);
188 writenum(buf[2], 37, 0x0F, stat.position-cdpTrackStarts[i-1], 10, 8, 0);
189 writenum(buf[2], 55, 0x0F, cdpTrackStarts[i]-cdpTrackStarts[i-1], 10, 8, 0);
190 } else {
191 writestring(buf[2], 22, 0x0F, gettimestr(cdpTrackStarts[i-1]+150, timestr), 8);
192 writestring(buf[2], 37, 0x0F, gettimestr(stat.position-cdpTrackStarts[i-1], timestr), 8);
193 writestring(buf[2], 55, 0x0F, gettimestr(cdpTrackStarts[i]-cdpTrackStarts[i-1], timestr), 8);
194 }
195 _writenum(buf[2], 71, 0x0F, (cdpTrackStarts[i]-cdpTrackStarts[i-1])*147/64, 10, 6);
196 }
197
cdaProcessKey(uint16_t key)198 static int cdaProcessKey(uint16_t key)
199 {
200 int i;
201 switch (key)
202 {
203 case KEY_ALT_K:
204 cpiKeyHelp('p', "Start/stop pause with fade");
205 cpiKeyHelp('P', "Start/stop pause with fade");
206 cpiKeyHelp(KEY_CTRL_P, "Start/stop pause");
207 cpiKeyHelp('t', "Toggle sector view mode");
208 cpiKeyHelp(KEY_DOWN, "Jump back (small)");
209 cpiKeyHelp(KEY_UP, "Jump forward (small)");
210 cpiKeyHelp(KEY_CTRL_DOWN, "Jump back (big)");
211 cpiKeyHelp(KEY_CTRL_UP, "Jump forward (big)");
212 cpiKeyHelp(KEY_LEFT, "Jump back");
213 cpiKeyHelp(KEY_RIGHT, "Jump forward");
214 cpiKeyHelp(KEY_HOME, "Jump to start of track");
215 cpiKeyHelp('<', "Jump track back");
216 cpiKeyHelp('>', "Jump track forward");
217 cpiKeyHelp(KEY_CTRL_LEFT, "Jump track back");
218 cpiKeyHelp(KEY_CTRL_RIGHT, "Jump track forward");
219 cpiKeyHelp(KEY_F(9), "Pitch speed down");
220 cpiKeyHelp(KEY_F(11), "Pitch speed down");
221 cpiKeyHelp(KEY_F(10), "Pitch speed up");
222 cpiKeyHelp(KEY_F(12), "Pitch speed up");
223 if (plrProcessKey)
224 plrProcessKey(key);
225 return 0;
226 case 'p': case 'P':
227 startpausefade();
228 break;
229 case KEY_CTRL_P:
230 pausefadedirect=0;
231 plPause=!plPause;
232 if (plPause)
233 cdPause(cdrom_fd);
234 else
235 cdRestart(cdrom_fd);
236
237 break;
238 case 't':
239 cdpViewSectors=!cdpViewSectors;
240 break;
241 /*
242 case 0x2000:
243 cdpPlayMode=1;
244 setnewpos=0;
245 basesec=cdpTrackStarts[0];
246 length=cdpTrackStarts[cdpTrackNum]-basesec;
247 // strcpy(name, "DISK");
248 break;
249 */
250 case KEY_DOWN:
251 newpos-=75;
252 setnewpos=1;
253 break;
254 case KEY_UP:
255 newpos+=75;
256 setnewpos=1;
257 break;
258 case KEY_LEFT:
259 newpos-=75*10;
260 setnewpos=1;
261 break;
262 case KEY_RIGHT:
263 newpos+=75*10;
264 setnewpos=1;
265 break;
266 case KEY_HOME:
267 if (!cdpPlayMode)
268 {
269 newpos=0;
270 setnewpos=1;
271 break;
272 }
273 for (i=1; i<=cdpTrackNum; i++)
274 if (newpos<(signed)(cdpTrackStarts[i]-basesec))
275 break;
276 newpos=cdpTrackStarts[i-1]-basesec;
277 setnewpos=1;
278 break;
279 case KEY_CTRL_UP:
280 /* case 0x8D00: //ctrl-up */
281 newpos-=60*75;
282 setnewpos=1;
283 break;
284 case KEY_CTRL_DOWN:
285 /*case 0x9100: //ctrl-down */
286 newpos+=60*75;
287 setnewpos=1;
288 break;
289 case KEY_CTRL_LEFT:
290 case '<':
291 if (!cdpPlayMode)
292 break;
293 for (i=2; i<=cdpTrackNum; i++)
294 if (newpos<(signed)(cdpTrackStarts[i]-basesec))
295 break;
296 newpos=cdpTrackStarts[i-2]-basesec;
297 setnewpos=1;
298 break;
299 case KEY_CTRL_RIGHT:
300 case '>':
301 if (!cdpPlayMode)
302 break;
303 for (i=1; i<=cdpTrackNum; i++)
304 if (newpos<(signed)(cdpTrackStarts[i]-basesec))
305 break;
306 newpos=cdpTrackStarts[i]-basesec;
307 setnewpos=1;
308 break;
309 /* TODO-keys
310 case 0x7700: //ctrl-home
311 newpos=0;
312 setnewpos=1;
313 break;*/
314 case KEY_F(9):
315 case KEY_F(11):
316 if ((speed-=finespeed)<16)
317 speed=16;
318 cdSetSpeed(speed);
319 break;
320 case KEY_F(10):
321 case KEY_F(12):
322 if ((speed+=finespeed)>2048)
323 speed=2048;
324 cdSetSpeed(speed);
325 break;
326 default:
327 if (smpProcessKey)
328 {
329 int ret=smpProcessKey(key);
330 if (ret==2)
331 cpiResetScreen();
332 if (ret)
333 return 1;
334 }
335 if (plrProcessKey)
336 {
337 int ret=plrProcessKey(key);
338 if (ret==2)
339 cpiResetScreen();
340 if (ret)
341 return 1;
342 }
343 return 0;
344 }
345 return 1;
346 }
347
cdaLooped(void)348 static int cdaLooped(void)
349 {
350 struct cdStat stat;
351
352 if (pausefadedirect)
353 dopausefade();
354
355 cdSetLoop(fsLoopMods);
356
357 cdIdle();
358
359 cdGetStatus(cdrom_fd, &stat);
360
361 /*
362 if (status->error&STATUS_ERROR)
363 return 1;
364 */
365
366 if (stat.looped)
367 return 1;
368
369 if (setnewpos)
370 {
371 if (newpos<0)
372 newpos=0;
373 if (newpos>=(signed)length)
374 {
375 if (fsLoopMods)
376 newpos=0;
377 else
378 return 1;
379 }
380 cdPause(cdrom_fd);
381 cdRestartAt(cdrom_fd, basesec+newpos /*, length-newpos*/);
382 if (plPause)
383 cdPause(cdrom_fd);
384 setnewpos=0;
385 } else
386 newpos=stat.position-basesec;
387
388 return 0;
389 }
390
cdaCloseFile(void)391 static void cdaCloseFile(void)
392 {
393 cdStop(cdrom_fd);
394 }
395
cdaOpenFile(struct moduleinfostruct * info,struct ocpfilehandle_t * file)396 static int cdaOpenFile (struct moduleinfostruct *info, struct ocpfilehandle_t *file)
397 {
398 char *name;
399 unsigned char tnum;
400 char buffer[64];
401
402 buffer[0] = 0;
403
404 file->seek_set (file, 0);
405 file->read (file, buffer, sizeof (buffer));
406 if (memcmp (buffer, "fd=", 3))
407 {
408 return -1;
409 }
410 cdrom_fd = atoi (buffer + 3);
411
412 dirdbGetName_internalstr (file->dirdb_ref, &name);
413
414 if (!strcmp(name, "DISK.CDA"))
415 tnum=0xFF;
416 else
417 if (!memcmp(name, "TRACK", 5)&&isdigit(name[5])&&isdigit(name[6])&&(name[7]=='.'))
418 tnum=(name[5]-'0')*10+(name[6]-'0');
419 else
420 return -1;
421
422 if (!cdIsCDDrive(cdrom_fd))
423 return -1;
424
425 cdpTrackNum=cdGetTracks(cdrom_fd, cdpTrackStarts, &cdpFirstTrack, CDROM_LEADOUT);
426
427 if (tnum!=0xFF)
428 {
429 if ((tnum<cdpFirstTrack)||(tnum>(cdpFirstTrack+cdpTrackNum)))
430 return -1;
431 cdpPlayMode=0;
432 basesec=cdpTrackStarts[tnum-cdpFirstTrack];
433 length=cdpTrackStarts[tnum-cdpFirstTrack+1]-basesec;
434 } else {
435 if (!cdpTrackNum)
436 return -1;
437 cdpPlayMode=1;
438 basesec=cdpTrackStarts[0];
439 length=cdpTrackStarts[cdpTrackNum+1]-basesec;
440 }
441
442 newpos=0;
443 setnewpos=1;
444 plPause=0;
445
446 plIsEnd=cdaLooped;
447 plProcessKey=cdaProcessKey;
448 plDrawGStrings=cdaDrawGStrings;
449
450 /* cdLockTray(cdpDrive, 1); */
451
452 strncpy(vdev, info->comment, 8);
453 vdev[7]=0;
454
455 if (cdPlay(cdrom_fd, basesec, length, file))
456 return -1;
457
458 normalize();
459 pausefadedirect=0;
460
461 return errOk;
462 }
463
464 struct cpifaceplayerstruct cdaPlayer = {cdaOpenFile, cdaCloseFile};
465 char *dllinfo = "";
466 struct linkinfostruct dllextinfo = {.name = "playcda", .desc = "OpenCP CDA Player (c) 1995-09 Niklas Beisert, Tammo Hinrichs, Stian Skjelstad", .ver = DLLVERSION, .size = 0};
467