/*	
 *	clipym.h
 *
 *	P/ECE YM (ST-Sound) Driver
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2004 Naoyuki Sawa
 *
 *	* Mon Apr 19 19:00:00 JST 2004 Naoyuki Sawa
 *	- 作成開始。
 */
#ifndef __CLIP_YM_H__
#define __CLIP_YM_H__

/****************************************************************************
 *	YMファイル仕様
 ****************************************************************************/

/* * 各フィールドのバイトオーダーはBigEndianです。
 *   ところが、YM3BHEADER.number_to_loop_the_songだけなぜかLittleEndianです。
 *   YM3b形式のファイルが30個位しかなく、調査数が少ないために確証が持てません。
 *   もしかしたら、YM3b形式でも物によってはBigEndianの場合があるかも知れません。
 *
 * * YMファイルの記述においてよく出てくる"VBL"という単語は、VBLANKの意味です。
 */

/* YM2より旧い形式のデータはほとんど存在しません。 */

/*
 *	YM3ファイルヘッダ
 */
typedef struct _YM3HEADER {
	unsigned char id_of_ym3_format			[4];	/* +0, 4: "YM3!" */
//	unsigned char all_ym2149_registers		[...];	/* interleaved only: {R0×VBL},{R1×VBL},...,{R13×VBL} */
} YM3HEADER;

/*
 *	YM3bファイルヘッダ
 */
typedef struct _YM3BHEADER {
	unsigned char id_of_ym3b_format			[4];	/* +0, 4: "YM3b" */
//	unsigned char all_ym2149_registers		[...];	/* interleaved only: {R0×VBL},{R1×VBL},...,{R13×VBL} */
//	unsigned char vbl_number_to_loop_the_song	[4];	/* なぜかこのフィールドだけLittleEndianで格納されてる!? */
} YM3BHEADER;

/*
 *	YM4ファイルヘッダ (この形式のデータはほとんど存在しません)
 */
typedef struct _YM4HEADER {
	unsigned char id_of_ym4_format			[4];	/* + 0,4: "YM4!" */
	unsigned char check_string			[8];	/* + 4,8: "LeOnArD!" */
	unsigned char nb_of_valid_vbl_of_the_file	[4];	/* +12,4: */
	unsigned char song_attributes			[4];	/* +16,4: */
	unsigned char nb_of_digidrum_sample		[4];	/* +20,4: */
	unsigned char vbl_number_to_loop_the_song	[4];	/* +24,4: */
//	for each digidrum sample {
//		unsigned char sample_size		[4];
//		unsigned char sample_data		[sample_size];
//	}
//	unsigned char name_of_the_song			[null-terminated];
//	unsigned char name_of_the_author		[null-terminated];
//	unsigned char comments				[null-terminated];
//	unsigned char all_ym2149_registers		[...];	/* interleaved: {R0×VBL},{R1×VBL},...,{R13×VBL} */
//								/* or non-interleaved: {R0,R1,...,R15}×VBL        */
//	unsigned char end_file_check			[4];	/* "End!" */
} YM4HEADER;

/*
 *	YM5ファイルヘッダ
 */
typedef struct _YM5HEADER {
	unsigned char id_of_ym5_format			[4];	/* + 0,4: "YM5!" */
	unsigned char check_string			[8];	/* + 4,8: "LeOnArD!" */
	unsigned char nb_of_valid_vbl_of_the_file	[4];	/* +12,4: */
	unsigned char song_attributes			[4];	/* +16,4: */
	unsigned char nb_of_digidrum_sample		[2];	/* +20,2: */
	unsigned char ym2149_external_frequency_in_hz	[4];	/* +22,4: */
	unsigned char player_frequency_in_hz		[2];	/* +26,2: */
	unsigned char vbl_number_to_loop_the_song	[4];	/* +28,4: */
	unsigned char size_of_future_additional_data	[2];	/* +32,2: */
//	for each digidrum sample {
//		unsigned char sample_size		[4];
//		unsigned char sample_data		[sample_size];
//	}
//	unsigned char name_of_the_song			[null-terminated];
//	unsigned char name_of_the_author		[null-terminated];
//	unsigned char comments				[null-terminated];
//	unsigned char all_ym2149_registers		[...];	/* interleaved: {R0×VBL},{R1×VBL},...,{R13×VBL} */
//								/* or non-interleaved: {R0,R1,...,R15}×VBL        */
//	unsigned char end_file_check			[4];	/* "End!" */
} YM5HEADER;

/* YM6のファイルヘッダ形式は、YM5と同じです。 */

/* YM{4,5}HEADER.song_attributes */
#define YM_INTERLEAVED_DATA_BLOCK			(1 << 0)
//#define YM_DIGIDRUM_SAMPLES_ARE_SIGNED_DATA		(1 << 1)	/* 未対応 */
//#define YM_DIGIDRUM_IS_ALREADY_IN_ST_4_BITS_FORMAT	(1 << 2)	/* 未対応 */

/****************************************************************************
 *	YMドライバ
 ****************************************************************************/

#define YMBUFLEN 320 /* =16000/50 … 1[tick](=1/50[sec])当たりのサンプル数 */

typedef struct _YMINFO {
	int nb_of_valid_vbl_of_the_file;		/* 全VBL数 */
	int vbl_number_to_loop_the_song;		/* ループ開始VBL番号 */
	int nb_of_registers_in_each_vbl;		/* 格納されているレジスタ数 (YM3!,YM3b:14 / YM4!,YM5!,YM6!:16) */
	int vbl_stride;					/* all_ym2149_register中で、同じVBLの次のレジスタへのオフセット */
	int register_stride;				/* all_ym2149_register中で、同じレジスタの次のVBLへのオフセット */

	int ym2149_external_frequency_in_hz;		/* YM2149入力クロック (ATARI-ST:2000000 / AMSTRAD CPC:1000000) */
	int player_frequency_in_hz;			/* VBLタイミング (通常50。VBL=100のファイルもわずかにあります) */

	char id_of_format[4 + 1];			/* YM3! / YM3b / YM4! / YM5! / YM6! */
	const char* name_of_the_song;			/* 曲名 */
	const char* name_of_the_author;			/* 作曲者名 */
	const char* comments;				/* コメント(YMファイル作成者など) */

	const unsigned char* all_ym2149_registers;	/* レジスタデータ先頭アドレス */
} YMINFO;

/*
 *	YMドライバ
 */
typedef struct _YMDRIVER {
	YMINFO info;		/* YMファイル情報 */
	//
	AY38910 ay38910;	/* AY-3-8910 (or YM2149) Chip */
	//
	DDA vbl_interval;	/* VBL間隔サンプル数調整用DDA */
	int vbl_progress;	/* 次回VBL発生までの残りサンプル数 */
	int vbl_position;	/* 次回のVBL位置 */
} YMDRIVER;

/*
 *	YMドライバ内部関数
 */
int ym_init(YMDRIVER* ym, const void* data, int len);
int ym_mix(YMDRIVER* ym, short wbuff[/*YMBUFLEN*/]);
int ym_stream_callback(short* wbuff, int param);
//
int ym_get_info_ym3(YMINFO* info, const YM3HEADER* header, int len);
int ym_get_info_ym3b(YMINFO* info, const YM3BHEADER* header, int len);
int ym_get_info_ym4(YMINFO* info, const YM4HEADER* header, int len);
int ym_get_info_ym5(YMINFO* info, const YM5HEADER* header, int len);

/****************************************************************************
 *	アプリケーション用関数
 ****************************************************************************/

/* YMファイル情報を取得します。
 * [in]
 *	info		YMファイル情報を受け取る変数へのポインタ。
 *	data		YMファイルデータ。(LZH展開済み)
 *	len		YMファイルデータサイズ。
 * [out]
 *	戻り値		情報を取得できたら、0を返します。
 *			情報を取得できなければ、-1を返します。
 *	*info		YMファイル情報を格納します。
 * [note]
 *	* この関数は演奏処理には関係ありません。
 *	  演奏中の曲名や作曲者名を画面表示するために利用してください。
 *	* YMドライバはLZH展開処理を行いません。
 *	  呼び出し側にてYMファイルデータをLZH展開し、展開データアドレスをym_get_info()関数に渡してください。
 */
int ym_get_info(YMINFO* info, const void* data, int len);

/* YMファイルの再生を開始します。
 * [in]
 *	data		YMファイルデータ。(LZH展開済み)
 *	len		YMファイルデータサイズ。
 * [out]
 *	戻り値		再生開始に成功したら、0を返します。
 *			再生開始できなければ、-1を返します。
 * [note]
 *	* この関数は内部でstream_play()を呼び出しています。
 *	* stream_play()を呼ぶと、サウンド割り込みベクタがフックされます。
 *	  プログラム終了前に必ずym_stop()を呼んで、ベクタを復元してください。
 *	* YMドライバはLZH展開処理を行いません。
 *	  呼び出し側にてYMファイルデータをLZH展開し、展開データアドレスをym_play()関数に渡してください。
 */
int ym_play(const void* data, int len);

/* YMファイルの再生を停止します。
 * [note]
 *	* 再生中でなければ、この関数は何もしません。
 */
void ym_stop();

#endif /*__CLIP_YM_H__*/
