/* ＦＭＢ＆ＰＭＢの中身を表示するプログラム */


#include	<stdio.h>
#include	<string.h>
#include	<stdlib.h>
#include	<ctype.h>


/* サウンドデータのヘッダ */
typedef struct
{
	char	name[8];	/* 名前 */
	long	id;			/* ID */
	long	len;		/* データの大きさ */
	long	lpt;		/* ループポインタ */
	long	llen;		/* ループレングス */
	int		freq;		/* サンプリング周波数(98倍されていて、KHz単位) */
	int		adj;		/* 原音の補正値 */
	char	note;		/* 基本音階 */
	char	a[3];		/* リザーブ*/
}SH;

/* インストゥルメントデータ */
typedef struct
{
	char	name[8];	/* 名前 */
	char	ra[8];		/* リザーブ */
	int		split[8];	/* スプリット1-8のサウンドを鳴らす音階の上限 */
	long	id[8];		/* スプリット1-8のサウンドのID */
	char	env[8][8];	/* エンベロープ */
}IDAT;


FILE	*fp;
char	iname[32][9];	/* PMBのインストゥルメントデータの名前 */
char	sname[128][9];	/* PMBのサウンドデータの名前 */
char	snote[128];		/* 各SNDデータの基本音階 */
long	sid[128];		/* 各SNDデータのID */
char	nt[12][3]=	{	"c ","c+","d ","d+",
						"e ","f ","f+","g ",
						"g+","a ","a+","b "	};




/* 文字数を合わせる */
void	adjustStr8(char *buf)
{
	int		j,k;
	
	for(j=0;j<8;j++)
	{
		if (buf[j]==0)
		{
			for (k=j;k<8;k++)
				buf[k]=0x20;
		}
	}
	buf[8]=0;
	return;
}




/* IDから名前を取り出す */
int		getSname(char *buf,long id,int snum)
{
	int		i;
	
	for (i=0;i<snum;i++)
	{
		if (sid[i]==id)
		{
			strcpy(buf,sname[i]);
			return(0);
		}
	}
	strcpy(buf,"Not use.");
	return(1);
}




/* ノートナンバー変換 */
void	noteCnv(char *buf,int note)
{
	if (note<129)
		sprintf(buf,"o%c%s",('0'-1+note/12),nt[note%12]);
	else
		strcpy(buf,"nil.     ");
	return;
}



void	PMBread(int wide)
{
	int		i,j;
	int		snum=0;		/* サウンドデータの数 */
	SH		head;		/* サウンドデータのヘッダ */
	IDAT	dat;		/* インストゥルメントデータ */
	char	buf[9];		/* 汎用文字列格納バッファ */
	char	n[4];		/* ノートナンバーをo5cとかに直したもの。 */
	
	fseek(fp,8,SEEK_SET);
	
	/* まず、inameの取得 */
	for (i=0;i<32;i++)
	{
		if (fread(buf,1,8,fp)<8)
		{	printf("PMBデータが変です。\n");	return;	}
		adjustStr8(buf);
		strcpy(iname[i],buf);
		fseek(fp,120,SEEK_CUR);
	}
	
	/* 次にsnameの取得 */
	fread(&head,1,sizeof(SH),fp);
	for (i=0; (i<128 && (!(feof(fp))) ) ; i++)
	{
		strncpy(buf,head.name,8);
		adjustStr8(buf);
		strcpy(sname[i],buf);
		snote[i]=head.note;
		snum++;
		sid[i]=head.id;
		fseek(fp,head.len,SEEK_CUR);
		fread(&head,1,sizeof(SH),fp);
	}
	
	/* 表示 */
	printf("●　name of instruments\n\n");
	for (i=0;i<32;i++)
	{
		if ((i+1)%wide)
			printf("%03d:%s ",i,iname[i]);
		else
			printf("%03d:%s\n",i,iname[i]);
	}
	printf("\n\n\n\n");
	
	printf("●　name of SND\n\n");
	for (i=0;i<snum;i++)
	{
		if ((i+1)%wide)
			printf("%03d:%s ",i,sname[i]);
		else
			printf("%03d:%s\n",i,sname[i]);
	}
	printf("\n\n\n\n");
	
	printf("●  information about split\n\n");
	fseek(fp,8,SEEK_SET);
	for (i=0;i<32;i++)
	{
		fread(&dat,1,sizeof(IDAT),fp);
		printf("  No%03d:%s               TL  AR  DR  SL  SR  RR\n",i,iname[i]);
		for(j=0;j<8;j++)
		{
			getSname(buf,dat.id[j],snum);
			noteCnv(n,dat.split[j]);
			printf("    split%c:〜%s:%s",('1'+j),n,buf );
			printf("    %03d %03d %03d %03d %03d %03d\n",dat.env[j][0],dat.env[j][1],dat.env[j][2],dat.env[j][3],dat.env[j][4],dat.env[j][5]);
		}
		printf("\n");
	}
	
	return;
}




void	FMBread(int wide)
{
	int		i;
	char	buf[9];
	
	if (fread(buf,1,8,fp)<8)
	{	printf("\n\nFMBファイルが変です。\n");	return;	}
	buf[8]=0;
	
	for(i=0;i<128;i++)
	{
		if (fread(buf,1,8,fp)<8)
		{	printf("\n\nFMBファイルが変です。\n");	return;	}
		
		adjustStr8(buf);
		
		if ((i+1) % wide)
			printf("%03d:%s ",i,buf);
		else
			printf("%03d:%s\n",i,buf);
		fseek(fp,40,SEEK_CUR);
	}
	return;
}




/* 拡張子を取り出してextに格納 */
int		MU_getExtName(char *fname,char *ext)
{
	char	*s;
	int		i;
	
	
	for (s=fname;(*s!='.' && *s!=0);s++)
		;
	s++;
	
	if (strlen(s)>3)
	{
		puts("なんだその拡張子名は");
		exit(1);
	}
	
	strcpy(ext,s);
	
	for (i=0;i<strlen(ext);i++)
		ext[i]=(tolower(ext[i]));
	
	return(0);
}



int		main(int argc,char *argv[])
{
	int		r=0;
	int		wide;
	char	ext[4];
	
	if (argc<2)
	{
		label0:;
		printf("使用法: fp [オプション] 読み込むファイル名 \n");
		printf("\n*****オプション\n");
		printf("-Xn...何列で表示するか(省略値は6) \n");
		printf("\n使用例: fp -x4 aaa.fmb \n");
		printf("      (横四列でaaa.fmbの音色一覧を表示\n");
		return(1);
	}
	
	if (argc>2)
	{
		if ( argv[1][0]=='-' || argv[1][0]=='/' )
		{
			if (argv[1][1]=='x' || argv[1][1]=='X' )
			{
				wide=atoi(&argv[1][2]);
				r++;
			}
			else
			{
				printf("オプションエラー");
				return(1);
			}
		}
		else
			goto label0;
	}
	else
		wide=6;
	
	if ((fp=fopen(argv[r+1],"rb"))==NULL)
	{
		printf("ファイルエラー♪\n");
		return(1);
	}
	
	MU_getExtName(argv[r+1],ext);
	
	if (strcmp(ext,"fmb")==0)
		FMBread(wide);
	else if (strcmp(ext,"pmb")==0)
		PMBread(wide);
	else
	{
		printf("このファイルは本プログラムの扱う範疇を逸しています。\n");
		fclose(fp);
		return(1);
	}
	
	fclose(fp);
	return(0);
}

