/*																	*/
/*			Cdur.C			( Cdur.EXE LSI-C86 用ソース)			*/
/*																	*/
/*				v1.00	90/11/24	By T.Takasaka					*/
/*				v1.01	90/12/12	bugfix							*/
/*									一部アセンブラ化(cdstop)		*/
/*									パラメータ数値の範囲検査をする	*/
/*				v1.02	90/12/13	STAT をつける					*/
/*				v1.03	90/12/30	vol をつける 					*/
/*				v1.04	91/01/03	パラメータ無の時cd演奏中		*/
/*									なら､ 新規に演奏しない			*/
/*				v1.05	91/07/07	パラメータ無の時でCD交換時には	*/
/*									演奏開始しないのを直した		*/
/*																	*/
/*																	*/
/*								TAKACHAN ( IMA00356   ひかりNET )	*/
/*								おくと	 ( PEE01566 NIFTY-Serve )	*/
/*																	*/
/*						PS. C-Dur は ドイツ語で ハ長調の意味です	*/

#define Cdur_version "v1.05"
#define Cdur_date    "91/07/07"

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <machine.h>

#define chkcode(track) ((cd_info.cd_time[(track)-1].cd_min) & 0x80) 
#define	cd_all_flame \
          (cd_info.all_min*4500+cd_info.all_sec*75+cd_info.all_flame)

#define	VOL_MAX 63
#define VOL1_DAT 0x04e0
#define VOL1_COM 0x04e1
#define VOL2_DAT 0x04e2
#define VOL2_COM 0x04e3


typedef	struct{
					unsigned char cd_min,cd_sec,cd_flame;
				}	CD_TIME;

typedef	struct{
					CD_TIME start_t,end_t;
				}	ENSOU_T;

typedef	struct{
					unsigned char dummy1,cd_flame,dummy2;
					CD_TIME track_t;
					unsigned char	dummy3;
					CD_TIME disk_t;
				}	ENSOU_STAT;

typedef struct{
					unsigned char cd_type,start_track,end_track;
					unsigned char all_min,all_sec,all_flame;
					CD_TIME		cd_time[98];
				}	TOC;

int setvol(int vol_no,int left,int right)
/* ボリュームセット 
		vol_no = 0 : line in
		vol_no = 1 : cd
		vol_no = 2 : mic
		vol_no = 3 : modem
*/
{
	unsigned char mix;

	mix  = ((left + right)/2) & VOL_MAX ;
	left = left & VOL_MAX;
	right = right & VOL_MAX;

	switch (vol_no)
	{
	case	0:
		if ( left > 0 ){
			outp( VOL1_COM , 0x04 );
		} else {
			outp( VOL1_COM , 0x00 );
		}	
		outp( VOL1_DAT , (unsigned char)left  );
		if ( right > 0 ){
			outp( VOL1_COM , 0x05 );
		} else {
			outp( VOL1_COM , 0x01 );
		}	
		outp( VOL1_DAT , (unsigned char)right  );
			if ( left == right ){
	printf ("\n\x1b[32mＬＩＮＥのｖｏｌｕｍｅを %d に設定しました｡\x1b[0m\n"
																		,left);
			}else{ 
printf("\n\x1b[32mＬＩＮＥのｖｏｌｕｍｅを 左:%d 右:%d に設定しました｡\x1b[0m\n"																,left,right);
			}	
		break;
	case	1:
		if ( left > 0 ){
			outp( VOL2_COM , 0x04 );
		} else {
			outp( VOL2_COM , 0x00 );
		}	
			outp( VOL2_DAT , (unsigned char)left  );
		if ( right > 0 ){
			outp( VOL2_COM , 0x05 );
		} else {
			outp( VOL2_COM , 0x01 );
		}	
			outp( VOL2_DAT , (unsigned char)right  );
			if ( left == right ){
		printf ("\n\x1b[32mＣＤのｖｏｌｕｍｅを %d に設定しました｡\x1b[0m\n"
																		,left);
			}else{ 
printf ("\n\x1b[32mＣＤのｖｏｌｕｍｅを 左:%d 右:%d に設定しました｡\x1b[0m\n"
																,left,right);
			}	
		break;
	case	2:
		if ( mix > 0 ){
			outp( VOL2_COM , 0x02 );
			outp( VOL2_DAT , mix  );
		} else {
			outp( VOL2_COM , 0x00 );
		}	
		printf ("\n\x1b[32mＭＩＣのｖｏｌｕｍｅを %d に設定しました｡\x1b[0m\n"
									,mix );
		break;
	case	3:
		if ( mix > 0 ){
			outp( VOL2_COM , 0x03 );
			outp( VOL2_DAT , mix  );
		} else {
			outp( VOL2_COM , 0x00 );
		}	
	printf ("\n\x1b[32mＭＯＤＥＭのｖｏｌｕｍｅを %d に設定しました｡\x1b[0m\n"
									,mix );
		break;
	default:
		return(-1);
	}
return(0);
}

int get_cd_stat()
{
	union	REGS	reg;
	struct	SREGS	sreg;
	ENSOU_STAT      cd_stat;	

	reg.x.ax = 0x53c0;
	reg.x.cx = 0x0000;
	reg.x.di = FP_OFF(&cd_stat);
    sreg.ds	 = FP_SEG(&cd_stat);
		
	int86x(0x93,&reg,&reg,&sreg) ;

	if ( reg.h.ah == 0 ){
		if ( reg.h.al != 0 ) {
			printf("\n %d 曲目を演奏しています。ＣＤ先頭から %d分 %d秒\n"
				,cd_stat.cd_flame,cd_stat.disk_t.cd_min,cd_stat.disk_t.cd_sec);
		}			
		else {
			printf("\nＣＤを演奏していません。\n");
		}
	}
	return( (reg.h.ah == 0x80) ? reg.h.ah * 256 + reg.h.cl : reg.x.ax ); 
}
int	read_cd_info(TOC *cd_info)
/*											*/
{
	union	REGS	reg;
	struct SREGS	sreg;

	reg.x.ax = 0x54c0;
	reg.x.cx = 0x0000;
	reg.x.di = FP_OFF(cd_info);
    sreg.ds	 = FP_SEG(cd_info);

	int86x(0x93,&reg,&reg,&sreg) ;
	
	return( (reg.h.ah == 0x80) ? reg.h.ah * 256 + reg.h.cl : reg.h.ah *256 ); 

}

int	cd_stop(); /* アセンブラ化しました cd_stop.a86 */
/*
{
	union	REGS	reg;

	reg.x.ax = 0x52c0;
	reg.x.cx = 0x0000;

	int86(0x93,&reg,&reg) ;
	
return( (reg.h.ah == 0x80) ? reg.h.ah * 256 + reg.h.cl : reg.h.ah *256 ); 

}
*/

int		_asm_time(char *, int );

#define	stop_time_asm(c) _asm_time("\n\
\tMOV\tCH,255\n\
\tMOV\tCL,AL\n\
\tMOV\tAX,21184\n\
\tINT\t147\n\
\tXOR\tAL,AL\n\
\tCMP\tAH,128\n\
\tJNE\t__aaa\n\
\tMOV\tAL,CL\n\
__aaa:\t", c )

/* インラインアセンブラ化したけどあまり意味がないなぁ */	

int	cd_time(int time)
{
	int	err_v;
	
	if	( ( err_v = stop_time_asm( time ) ) == 0 ){
		if	( time != 0 )
	printf ("\n\x1b[32mＣＤドライブの停止時間を %d 秒に設定しました｡\x1b[0m\n"
																		,time);
		else
	printf ("\n\x1b[32mＣＤドライブが停止しないように設定しました｡\x1b[0m\n")			;	
	}
return( err_v ); 
}	
/*
{
	union	REGS	reg;

	reg.x.ax = 0x52c0;
	reg.x.cx = ( 0xff00 | ( time & 0x00ff) ) ;
	
	int86(0x93,&reg,&reg) ;

	if	( reg.h.ah== 0 ){
		if	( time != 0 )
	printf ("\n\x1b[32mＣＤドライブの停止時間を %d 秒に設定しました｡\x1b[0m\n"
																		,time);
		else
	printf ("\n\x1b[32mＣＤドライブが停止しないように設定しました｡\x1b[0m\n")			;	
	}
return( (reg.h.ah == 0x80) ? reg.h.ah * 256 + reg.h.cl : reg.h.ah *256 ); 
}
*/
int	cd_start(ENSOU_T *ensou_time,int kaisuu)
{
	union	REGS	reg;
	struct SREGS	sreg;

	reg.x.ax = 0x50c0;

		if 		( kaisuu == 0 )
				reg.x.cx = 0xff01 ;
		else if	( kaisuu == 1 )
				reg.x.cx = 0x0001 ;
		else {
				reg.x.cx = 0xfe01;
				reg.h.bh = kaisuu-1;
		}

	reg.x.di = FP_OFF(ensou_time);
    sreg.ds	 = FP_SEG(ensou_time);
	
	int86x(0x93,&reg,&reg,&sreg);
	
	return( (reg.h.ah == 0x80) ? reg.h.ah*256 + reg.h.cl : reg.h.ah *256 ); 
}

long int calc_flame(CD_TIME time)
{
	return((time.cd_min & 0x7f)*60*75+time.cd_sec*75+time.cd_flame);
}

CD_TIME calc_time(long int flame)
{
	CD_TIME time;

	time.cd_min=flame/(60*75);
	time.cd_sec=(flame-time.cd_min*60*75)/75;
	time.cd_flame=flame-time.cd_min*75*60-time.cd_sec*75;

	return(time);
}

int calc_ensou(int start,int end,TOC cd_info,ENSOU_T *ensou)
/*
	入力 演奏開始track no. 演奏終了track no.
			cd_info 
*/
{
	if (start<cd_info.start_track)	start=cd_info.start_track;
	if	(chkcode(start) !=0)		start++; 
	if	(start>cd_info.end_track)	start=cd_info.end_track;
	if	(start==cd_info.end_track && chkcode(start)!=0)
									return(-1);

	if	(end>cd_info.end_track)		end=cd_info.end_track;
	if	(chkcode(end) !=0)			end--; 
	if	(end<cd_info.start_track)	end=cd_info.start_track;
	if	(end==cd_info.start_track && chkcode(end)!=0)
									return(-1);
	if	(start>end)					return(-1);	

		(*ensou).start_t=cd_info.cd_time[start-1];
	if (end==cd_info.end_track)
	    (*ensou).end_t=calc_time(cd_all_flame -1);
	else
		(*ensou).end_t=calc_time(calc_flame(cd_info.cd_time[end])-1);

	return(start*256+end);
}	

void	err_r( int erf )
{
	if ( erf == 0x0200      )
				printf ("\n\x1b[31mデバイス番号エラー\x1b[0m\n");
	if ( erf == 0x1000      )
				printf ("\n\x1b[31m音楽演奏中\x1b[0m\n");
	if ( erf == 0x8001 )
				printf ("\n\x1b[31mＣＤがはいっていません｡\x1b[0m\n");
	if ( erf == 0x8002  )
				printf ("\n\x1b[31mパラメータエラー\x1b[0m\n");
	if ( erf == 0x8004  )
				printf ("\n\x1b[31mドライブがつながっていません｡\x1b[0m\n");
	if ( erf == 0x8008  )
				printf ("\n\x1b[31mコマンド異常終了\x1b[0m\n");
	if ( erf == 0x8010  )
				printf ("\n\x1b[31mＣＤが読み取れません｡\x1b[0m\n");
	if ( erf == 0x8080 	)
				printf ("\n\x1b[31mＣＤが交換されました｡\x1b[0m\n");
	if (erf == -1       ){
puts("                                                          ");
puts("  書式    Cdur        CD を 全曲リピート再生              ");
puts("          Cdur STOP   CD を 停止する                      ");
puts("          Cdur PLAY [ start [ end [ loop ]]]              ");
puts("                      CD を start曲目から end曲目まで     ");
puts("                      loop 回 再生                        ");
puts("                      loop=0 で止めるまで連続再生         ");
puts("          Cdur TIME   [time]                              ");
puts("                      CDが停止するまでの時間を設定する    ");
puts("                      timeの単位は秒､ 0 で止まらない      ");
puts("          Cdur STAT   CD を 演奏情報を表示する            ");
puts("          Cdur VOL  [ [ { CD | LINE | MIC | MODEM }       ");
puts("                        [ left_vol  [ right_vol ] ] ] ]   ");
puts("                                                          ");
}

}

int cd_play_main(int start,int end,int kaisuu)
{
	ENSOU_T ensou_time;
	TOC 	cd_info;
	int		tim,erf,erf1;
	
	cd_stop();
	for (tim=0,erf=1;tim<2 && erf!=0 ;tim++)
		erf=read_cd_info(&cd_info);

	if ( erf!= 0 )	return(erf);
	
	if ((erf1=calc_ensou(start,end,cd_info,&ensou_time))==-1 )
				return(0x8002);
	
	if ((erf=cd_start(&ensou_time,kaisuu))!=0) return(erf);

	if ((erf1/256)==(erf1 % 256))
		printf("\n\x1b[36m %d 曲目を",(erf1 / 256));
	else
	   printf("\n\x1b[36m %d 曲目から %d 曲目まで",(erf1/256),(erf1 % 256));

	if ( kaisuu == 0)
		printf("繰り返し演奏します\x1b[0m\n");
	else if (kaisuu==1)  
		printf("演奏します\x1b[0m\n");
	else if (kaisuu>=1)  
		printf(" %d 回演奏します\x1b[0m\n",kaisuu);
	return(0);
}




main(int argc,char *argv[])
{
	int		start=1, end=99, kaisuu=1, time=0 ,erf=-1;
	int		vol_set = 1,vol_left=VOL_MAX,vol_right=VOL_MAX;		

	printf("\n\x1b[32m");
	printf("＊＊＊　\x1b[36mＣｄｕｒ．ｅｘｅ \x1b[31m♪\x1b[32m    ");
	printf( Cdur_version );
	printf( "   " );
	printf( Cdur_date );
	printf("    By おくと ＊＊＊\n\x1b[0m");

	if (argc==1){
		erf=get_cd_stat();	
		if (erf == 0x0000 ){ 	
			erf=cd_play_main(0,99,0);
		}
		if (erf == 0x8080){ 	
	 		erf=get_cd_stat();	
			erf=cd_play_main(0,99,0);
		}
	}
	if (argc>=2 && strcmpi(argv[1],"stop")== 0 ){
			erf=cd_stop(); 	
			if	( erf== 0 )
				printf ("\n\x1b[1;34mＣＤを停止しました｡\x1b[0m\n");
	}
	if (argc>=2 && strcmpi(argv[1],"play")== 0 ){
		if	(argc>=3)	start	= atoi(argv[2]) ;
		if	(argc>=4)	end		= atoi(argv[3])	;
		if	(argc>=5)	kaisuu	= atoi(argv[4]) ;
		if ( 0<=start && start<=99 && 0<=end && end<=99 
						&& 0<=kaisuu && kaisuu<=256 )
		erf=cd_play_main(start,end,kaisuu);
	}
	if (argc>=2 && strcmpi(argv[1],"time")== 0 ){
		if	(argc>=3)					 time	= atoi(argv[2]) ;
		if	( 0 <= time && time <= 255 ) erf	= cd_time(time) ;
	}

	if ( argc==2 && strcmpi(argv[1],"stat")== 0 ){
			erf=get_cd_stat() & 0xff00 ; 	
	}

	if ( argc>=2 && strcmpi(argv[1],"vol")== 0 ){
			if ( argc== 5 ){
				vol_left = atoi(argv[3]) ; 
				vol_right = atoi(argv[4]); 
			}
			else if ( argc == 4 ) { 
				vol_left=vol_right=atoi(argv[3]) ;
			}
			
			if ( argc>=3 && strcmpi(argv[2],"cd") == 0 ) 		vol_set=1; 
			else if ( argc>=3 && strcmpi(argv[2],"line") == 0 ) vol_set=0;
			else if ( argc>=3 && strcmpi(argv[2],"mic") == 0 ) 	vol_set=2;
			else if ( argc>=3 && strcmpi(argv[2],"modem") == 0 ) vol_set=3;
 	
			if ( 0<= vol_left && vol_left<=VOL_MAX 
									&& 0<=vol_right && vol_right<=VOL_MAX)
				erf = setvol( vol_set , vol_left , vol_right );
	}

	err_r(erf);
}
