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