/*******************************************
 *   FM-Towns CD-ROM BIOS access library   *
 *         Program made by K,Ajima         *
 *      Copyright  ajiyan soft l.t.d.      *
 *******************************************/



/*** cdr *****************************************************************

  ＦＭ−ＴｏｗｎｓのＣＤ−ＲＯＭ  ＢＩＯＳへのインターフェイスを取る、ライ
ブラリです。
  ソースファイルにｃｄｒ．ｈをインクルードし、ｘｃｄｒ．ｌｉｂとリンクしま
す。
  本ライブラリの使用により、ＣＤ−ＲＯＭが使用できます。

ｃｄｒ＿ｘｘｘｘｘ（）			：  ＣＤ−ＲＯＭ  ＢＩＯＳを直接扱う低レベ
									ル関数

ｅｃｄｒ＿ｘｘｘｘｘ（）		：  ＣＤ−ＲＯＭ  ＢＩＯＳを利用した独自の
									高レベル関数

ｉｎｃｄｒ＿ｘｘｘｘｘ（）		：  ライブラリ内で使用する内部関数

**************************************************************************/



#include <stdio.h>
#include <dos.h>
#include <malloc.h>
#include <memory.h>



#pragma pack(1)										/* 構造体のアライメントオフ */



/* cdr_xxxxx() 返値 */
#define CDR_NO_ERR			0x00U					/* エラー無し */
#define CDR_DEV_NO_ERR		0x02U					/* デバイスNOエラー */
#define CDR_PLAYING			0x10U					/* 再生中 */
#define CDR_PAUSE			0x22U					/* 一時停止中 */
#define CDR_NOPAUSE			0x23U					/* 一時停止中ではない */
#define CDR_HARD_ERR		0x80U					/* ハードエラー */



/* cdr_errno : cdr_xxxxx() の返値が 0x80の場合有効 */
#define CDRHE_CHANGE_MEDIA	0x80U					/* メディア交換有り */
#define CDRHE_HARD_ERR		0x20U					/* ハードエラー */
#define CDRHE_MEDIA_ERR		0x10U					/* メディアエラー */
#define CDRHE_BAT_COMMAND	0x08U					/* コマンドエラー */
#define CDRHE_DRIVE_CONNECT	0x04U					/* ドライブ接続エラー */
#define CDRHE_PARAMETER_ERR	0x02U					/* パラメータエラー */
#define CDRHE_DRIVE_STANDBY	0x01U					/* ドライブスタンバイエラー */

unsigned int cdr_errno;								/* CD-ROM BIOS ハードエラー番号 */



/* ecdr_xxxxx() 返値 */
#define ECDR_OUT_MEM		0xa0U					/* メモリが足りない */
#define ECDR_NUM_ERR		0xa1U					/* 演奏曲番エラー */



/* ディスク･トラック タイプ */
#define ECDR_DATAT			0x02U					/* データ */
#define ECDR_MUSICT			0x01U					/* 音楽 */



#define CDR_DEVICE_NO		(unsigned char)0xc0		/* CD-ROM デバイス番号 */



typedef struct {									/* CD-ROM トラックタイムデータ */
	unsigned char minutes;
	unsigned char seconds;
	unsigned char flames;
} CDR_TIME_DATA;



typedef struct {									/* CD-ROM ディスクデータ */
	unsigned char disk_type;
	unsigned char start_track;
	unsigned char end_track;
	CDR_TIME_DATA disk_data;
	CDR_TIME_DATA track_data[99];
} CDR_DISK_DATA;



typedef struct {
	unsigned char researve_1;
	unsigned char playing_no;
	unsigned char researve_2;
	CDR_TIME_DATA track_data;
	unsigned char researve_3;
	CDR_TIME_DATA disk_data;
} CDR_PLAYING_DATA;



/********************************************************************
 *
 *   incdr_xxxxx() 関数群
 *
 *
 *
 *
 */



/********************************************************************
 *   時刻計算
 *     1. 時刻のポインタ1
 *     2. 計算フレーム
 *     3. 結果を格納するポインタ
 ********************************************************************/
void _fastcall incdr_time_data_expro(
					CDR_TIME_DATA * cdr_src,
					long cdr_expro_flames,
					CDR_TIME_DATA * cdr_dest)
{
	long flames;

	flames=(long)cdr_src->flames+
		   (long)cdr_src->seconds*75U+
		   (long)cdr_src->minutes*60U*75U+
		   cdr_expro_flames;

	cdr_dest->minutes=(unsigned char)( flames/(60U*75U) );
	cdr_dest->seconds=(unsigned char)( (flames/75U)%60U );
	cdr_dest->flames =(unsigned char)( flames%75U );
}



/********************************************************************
 *   CDR_TIME_DATA の確保
 *     確保するブロック数
 *     ret: NULL エラー
 *          else 確保したポインタ
 ********************************************************************/
CDR_TIME_DATA * _fastcall incdr_alloc_cdr_time_data(unsigned int cdr_block)
{
	return(malloc(sizeof(CDR_TIME_DATA)*cdr_block));
}



/********************************************************************
 *   CDR_TIMA_DATA の複写
 *     1. コピー先のポインタ
 *     2. コピーもとのポインタ
 ********************************************************************/
void _fastcall incdr_cpy_cdr_time_data(
					CDR_TIME_DATA *cdr_dest,
					CDR_TIME_DATA *cdr_src)
{
	memcpy(cdr_dest,cdr_src,sizeof(CDR_TIME_DATA));
}



/********************************************************************
 *
 *   cdr_xxxxx() 関数群
 *
 *
 *
 *
 */



/********************************************************************
 *   CD ディスク情報読み込み
 *     1. デバイス番号
 *     2. CDR_DISK_DATA のポインタ
 ********************************************************************/
unsigned char _fastcall cdr_info(
					unsigned char cdr_device_no,
					CDR_DISK_DATA *cdr_disk_data)
{
	union REGS regs;
	struct SREGS sregs;
	void _far * adr;

	adr=(void _far *)cdr_disk_data;

	regs.h.ah=0x54;
	regs.h.al=cdr_device_no;
	regs.x.cx=0x0000;
	regs.x.di=FP_OFF(adr);

	segread(&sregs);
	sregs.ds=FP_SEG(adr);

	int86x(0x93,&regs,&regs,&sregs);

	cdr_errno=regs.x.cx;
	return(regs.h.ah);
}



/********************************************************************
 *   CD 演奏
 *     1. デバイス番号
 *     2. CDR_TIME_DATA 演奏情報のポインタ
 ********************************************************************/
unsigned char _fastcall cdr_play(
					unsigned char cdr_device_no,
					CDR_TIME_DATA * cdr_time_data)
{
	union REGS regs;
	struct SREGS sregs;
	void _far * adr;

	adr=(void _far *)cdr_time_data;

	regs.h.ah=0x50;
	regs.h.al=cdr_device_no;
	regs.x.cx=0x0001;
	regs.x.di=FP_OFF(adr);

	segread(&sregs);
	sregs.ds=FP_SEG(adr);

	int86x(0x93,&regs,&regs,&sregs);

	cdr_errno=regs.x.cx;
	return(regs.h.ah);
}



/********************************************************************
 *   CD 再生 ( 全リピート )
 *     1. デバイス番号
 *     2. CDR_TIME_DATA 演奏情報のポインタ
 ********************************************************************/
unsigned char _fastcall cdr_play_rep_all(
					unsigned char cdr_device_no,
					CDR_TIME_DATA *cdr_time_data)
{
	union REGS regs;
	struct SREGS sregs;
	void _far * adr;

	adr=(void _far *)cdr_time_data;

	regs.h.ah=0x50;
	regs.h.al=cdr_device_no;
	regs.x.cx=0xff01;
	regs.x.di=FP_OFF(adr);

	segread(&sregs);
	sregs.ds=FP_SEG(adr);

	int86x(0x93,&regs,&regs,&sregs);

	cdr_errno=regs.x.cx;
	return(regs.h.ah);
}



/********************************************************************
 *   CD 再生 ( リピート回数指定 )
 *     1. デバイス番号
 *     2. CDR_TIME_DATA 演奏情報のポインタ
 *     3. リピート回数
 ********************************************************************/
unsigned char _fastcall cdr_play_num_rep(
					unsigned char cdr_device_no,
					CDR_TIME_DATA *cdr_time_data,
					unsigned char cdr_rep)
{
	union REGS regs;
	struct SREGS sregs;
	void _far * adr;

	adr=(void _far *)cdr_time_data;

	regs.h.ah=0x50;
	regs.h.al=cdr_device_no;
	regs.h.bh=cdr_rep-(unsigned char)1;
	regs.x.cx=0xfe01;
	regs.x.di=FP_OFF(adr);

	segread(&sregs);
	sregs.ds=FP_SEG(adr);

	int86x(0x93,&regs,&regs,&sregs);

	cdr_errno=regs.x.cx;
	return(regs.h.ah);
}



/********************************************************************
 *   CD 演奏情報読み込み
 *     1. デバイス番号
 *     2. CDR_TIME_DATA 演奏情報のポインタ
 *     3. CDR_PLAYING_DATA のポインタ
 *     4. 演奏情報を格納するポインタ
 ********************************************************************/
unsigned char _fastcall cdr_play_data(
					unsigned char cdr_device_no,
					CDR_TIME_DATA * cdr_time_data,
					CDR_PLAYING_DATA * cdr_playing_data,
					unsigned char * cdr_playing)
{
	union REGS regs;
	struct SREGS sregs;
	void _far * adr;



	adr=(void _far *)cdr_time_data;

	regs.h.ah=0x51;
	regs.h.al=cdr_device_no;
	regs.x.cx=0x0001;
	regs.x.di=FP_OFF(adr);

	segread(&sregs);
	sregs.ds=FP_SEG(adr);

	int86x(0x93,&regs,&regs,&sregs);

	cdr_errno=regs.x.cx;
	if(regs.h.ah!=CDR_NO_ERR) return(regs.h.ah);



	adr=(void _far *)cdr_playing_data;

	regs.h.ah=0x53;
	regs.h.al=cdr_device_no;
	regs.x.cx=0x0000;
	regs.x.di=FP_OFF(adr);

	segread(&sregs);
	sregs.ds=FP_SEG(adr);

	int86x(0x93,&regs,&regs,&sregs);

	*cdr_playing=regs.h.al;
	cdr_errno=regs.x.cx;
	return(regs.h.ah);
}



/********************************************************************
 *   CD 演奏停止
 *     1. デバイス番号
 ********************************************************************/
unsigned char _fastcall cdr_stop(unsigned char cdr_device_no)
{
	union REGS regs;

	regs.h.ah=0x52;
	regs.h.al=cdr_device_no;
	regs.h.ch=0x00;

	int86(0x93,&regs,&regs);

	cdr_errno=regs.x.cx;
	return(regs.h.ah);
}



/********************************************************************
 *   CD ドライブ回転停止時間の設定
 *     1. デバイス番号
 *     2. 停止時間 [s]
 ********************************************************************/
unsigned char _fastcall cdr_stop_time(
					unsigned char cdr_device_no,
					unsigned char cdr_stoptime)
{
	union REGS regs;

	regs.h.ah=0x52;
	regs.h.al=cdr_device_no;
	regs.h.ch=0xff;
	regs.h.cl=cdr_stoptime;

	int86(0x93,&regs,&regs);

	cdr_errno=regs.x.cx;
	return(regs.h.ah);
}



/********************************************************************
 *   CD 一時停止
 *     1. デバイス番号
 ********************************************************************/
unsigned char _fastcall cdr_pause(unsigned char cdr_device_no)
{
	union REGS regs;

	regs.h.ah=0x55;
	regs.h.al=cdr_device_no;
	regs.h.ch=0x00;

	int86(0x93,&regs,&regs);

	cdr_errno=regs.x.cx;
	return(regs.h.ah);
}



/********************************************************************
 *   CD 一時停止解除
 *     1. デバイス番号
 ********************************************************************/
unsigned char _fastcall cdr_replay(unsigned char cdr_device_no)
{
	union REGS regs;

	regs.h.ah=0x56;
	regs.h.al=cdr_device_no;
	regs.h.ch=0x00;

	int86(0x93,&regs,&regs);

	cdr_errno=regs.x.cx;
	return(regs.h.ah);
}



/********************************************************************
 *
 *   ecdr_xxxxx() 関数群
 *
 *
 *
 *
 */



/********************************************************************
 *   CD ディスクタイプの判定
 *     CDR_DISK_DATA のポインタ
 *     ret: ECDR_DATAT                データのみ
 *          ECDR_MUSICT               音楽のみ
 *          ECDR_DATAT | ECDR_MUSICT データ&音楽
 ********************************************************************/
unsigned char _fastcall ecdr_get_disk_type(CDR_DISK_DATA * cdr_disk_data)
{
	return(cdr_disk_data->disk_type);
}



/********************************************************************
 *   CD トラックタイプの判定
 *     CDR_TIME_DATA のポインタ
 *     ret: ECDR_DATAT                データトラック
 *          ECDR_MUSICT               音楽トラック
 ********************************************************************/
unsigned char _fastcall ecdr_get_track_type(CDR_TIME_DATA * cdr_time_data)
{
	if((cdr_time_data->minutes & 0x80)==0x80) {
		return(ECDR_DATAT);
	}
	else {
		return(ECDR_MUSICT);
	}
}



/********************************************************************
 *   CD 演奏
 *     1. 演奏開始 CDR_TIME_DATA のポインタ
 *     2. 演奏終了 CDR_TIME_DATA のポインタ
 ********************************************************************/
unsigned char _fastcall ecdr_play(
					CDR_TIME_DATA * cdr_start,
					CDR_TIME_DATA * cdr_end)
{
	CDR_TIME_DATA * cdr_alloc;
	unsigned char ret;

													/* cdr_alloc 確保 */
	if((cdr_alloc=incdr_alloc_cdr_time_data(2))==NULL) {
		return(ECDR_OUT_MEM);
	}

													/* 複写 */
	incdr_cpy_cdr_time_data(cdr_alloc  ,cdr_start);
	incdr_cpy_cdr_time_data(cdr_alloc+1,cdr_end  );

	ret=cdr_play(CDR_DEVICE_NO,cdr_alloc);			/* 演奏 */

	free(cdr_alloc);

	return(ret);
}



/********************************************************************
 *   CD 演奏 ( 全リピート )
 *     1. 演奏開始 CDR_TIME_DATA のポインタ
 *     2. 演奏終了 CDR_TIME_DATA のポインタ
 ********************************************************************/
unsigned char _fastcall ecdr_play_rep_all(
					CDR_TIME_DATA * cdr_start,
					CDR_TIME_DATA * cdr_end)
{
	CDR_TIME_DATA * cdr_alloc;
	unsigned char ret;

													/* cdr_alloc 確保 */
	if((cdr_alloc=incdr_alloc_cdr_time_data(2))==NULL) {
		return(ECDR_OUT_MEM);
	}

													/* 複写 */
	incdr_cpy_cdr_time_data(cdr_alloc  ,cdr_start);
	incdr_cpy_cdr_time_data(cdr_alloc+1,cdr_end  );

	ret=cdr_play_rep_all(CDR_DEVICE_NO,cdr_alloc);	/* 演奏 */

	free(cdr_alloc);

	return(ret);
}



/********************************************************************
 *   CD 演奏 ( リピート回数指定 )
 *     1. 演奏開始 CDR_TIME_DATA のポインタ
 *     2. 演奏終了 CDR_TIME_DATA のポインタ
 *     3. リピート回数
 ********************************************************************/
unsigned char _fastcall ecdr_play_num_rep(
					CDR_TIME_DATA * cdr_start,
					CDR_TIME_DATA *cdr_end,
					unsigned char cdr_rep)
{
	CDR_TIME_DATA * cdr_alloc;
	unsigned char ret;

													/* cdr_alloc 確保 */
	if((cdr_alloc=incdr_alloc_cdr_time_data(2))==NULL) {
		return(ECDR_OUT_MEM);
	}

													/* 複写 */
	incdr_cpy_cdr_time_data(cdr_alloc  ,cdr_start);
	incdr_cpy_cdr_time_data(cdr_alloc+1,cdr_end  );

													/* 演奏 */
	ret=cdr_play_num_rep(CDR_DEVICE_NO,cdr_alloc,cdr_rep);

	free(cdr_alloc);

	return(ret);
}



/********************************************************************
 *   CD 演奏
 *     1. 演奏開始曲番
 *     2. 演奏終了曲番
 *     3. CDR_DISK_DATA のポインタ
 ********************************************************************/
unsigned char _fastcall ecdr_play_bynum(
					unsigned int cdr_start,
					unsigned int cdr_end,
					CDR_DISK_DATA * cdr_disk_data)
{
	CDR_TIME_DATA * end,							/* 演奏終了時刻 */
				  * adr;							/* 演奏終了時刻算出用ワーク */
	unsigned char ret;

													/* 演奏曲番エラー判定 */
	if(cdr_start<cdr_disk_data->start_track ||
	   cdr_start>cdr_disk_data->end_track        ) {
		return(ECDR_NUM_ERR);
	}
	if(cdr_end<cdr_disk_data->start_track ||
	   cdr_end>cdr_disk_data->end_track        ) {
		return(ECDR_NUM_ERR);
	}

	if((end=incdr_alloc_cdr_time_data(1))==NULL) {	/* end 確保 */
		return(ECDR_OUT_MEM);
	}

													/* adr 算出 */
	if(cdr_end==cdr_disk_data->end_track) {
		adr=& cdr_disk_data->disk_data;					/* 最終曲 */
	}
	else {
		adr=& cdr_disk_data->track_data[cdr_end];		/* 以外 */
	}

	incdr_time_data_expro(adr,-1L,end);				/* end を求める */

													/* 演奏 */
	ret=ecdr_play(& cdr_disk_data->track_data[cdr_start-1],end);

	free(end);

	return(ret);
}



/********************************************************************
 *   CD 演奏 ( 全リピート )
 *     1. 演奏開始曲番
 *     2. 演奏終了曲番
 *     3. CDR_DISK_DATA のポインタ
 ********************************************************************/
unsigned char _fastcall ecdr_play_rep_all_bynum(
					unsigned int cdr_start,
					unsigned int cdr_end,
					CDR_DISK_DATA * cdr_disk_data)
{
	CDR_TIME_DATA * end,							/* 演奏終了時刻 */
				  * adr;							/* 演奏終了時刻算出用ワーク */
	unsigned char ret;

													/* 演奏曲番エラー判定 */
	if(cdr_start<cdr_disk_data->start_track ||
	   cdr_start>cdr_disk_data->end_track        ) {
		return(ECDR_NUM_ERR);
	}
	if(cdr_end<cdr_disk_data->start_track ||
	   cdr_end>cdr_disk_data->end_track        ) {
		return(ECDR_NUM_ERR);
	}

	if((end=incdr_alloc_cdr_time_data(1))==NULL) {	/* end 確保 */
		return(ECDR_OUT_MEM);
	}

													/* adr 算出 */
	if(cdr_end==cdr_disk_data->end_track) {
		adr=& cdr_disk_data->disk_data;					/* 最終曲 */
	}
	else {
		adr=& cdr_disk_data->track_data[cdr_end];		/* 以外 */
	}

	incdr_time_data_expro(adr,-1L,end);				/* end を求める */

													/* 演奏 */
	ret=ecdr_play_rep_all(& cdr_disk_data->track_data[cdr_start-1],end);

	free(end);

	return(ret);
}



/********************************************************************
 *   CD 演奏 ( リピート回数指定 )
 *     1. 演奏開始曲番
 *     2. 演奏終了曲番
 *     3. リピート回数
 *     4. CDR_DISK_DATA のポインタ
 ********************************************************************/
unsigned char _fastcall ecdr_play_num_rep_bynum(
					unsigned int cdr_start,
					unsigned int cdr_end,
					unsigned char cdr_rep,
					CDR_DISK_DATA * cdr_disk_data)
{
	CDR_TIME_DATA * end,							/* 演奏終了時刻 */
				  * adr;							/* 演奏終了時刻算出用ワーク */
	unsigned char ret;

													/* 演奏曲番エラー判定 */
	if(cdr_start<cdr_disk_data->start_track ||
	   cdr_start>cdr_disk_data->end_track        ) {
		return(ECDR_NUM_ERR);
	}
	if(cdr_end<cdr_disk_data->start_track ||
	   cdr_end>cdr_disk_data->end_track        ) {
		return(ECDR_NUM_ERR);
	}

	if((end=incdr_alloc_cdr_time_data(1))==NULL) {	/* end 確保 */
		return(ECDR_OUT_MEM);
	}

													/* adr 算出 */
	if(cdr_end==cdr_disk_data->end_track) {
		adr=& cdr_disk_data->disk_data;					/* 最終曲 */
	}
	else {
		adr=& cdr_disk_data->track_data[cdr_end];			/* 以外 */
	}

	incdr_time_data_expro(adr,-1L,end);				/* end を求める */

													/* 演奏 */
	ret=ecdr_play_num_rep(& cdr_disk_data->track_data[cdr_start-1],end,cdr_rep);

	free(end);

	return(ret);
}

