#include <stdio.h>

/* Instrument bank file header */
typedef struct {
   char      majorVersion;
   char      minorVersion;
   char      sig [6];            /* signature: "ADLIB-" */
   unsigned  nrDefined;          /* number of list entries used */
   unsigned  nrEntry;            /* number of total entries in list */
   long      offsetIndex;        /* offset in file of start of name list */
   long      offsetTimbre;       /* offset in file of start of data */
   char      filler [8];         /* must be zero */
} BankHeader;


/* Name of instrument with a pointer to its position in the file */
typedef struct {
   unsigned nrReference;       /* index into data section */
   char  usedFlag;             /* 0 if this entry is not used */
   char  TimbreName [9];       /* max 8 char's + NULL */
} BankEntry;


/* Operator structure */
typedef struct {
   char  ksl;
   char  freqMult;
   char  feedBack;              /* used by operator 0 only */
   char  attack;
   char  sustLevel;
   char  sustain;
   char  decay;
   char  release;
   char  output;
   char  am;
   char  vib;
   char  ksr;
   char  fm;                    /* used by operator 0 only */
} Operator;


typedef struct {
	char      mode;
	char      percVoice;
	Operator  op0;
	Operator  op1;
	char      wave0;            /* wave form for operator 0 */
	char      wave1;            /* wave form for operator 1 */
} PackedTimbre;

struct dat {
	char name[9];
	char pmode;
	int voicenum;
	unsigned idx;
};

BankHeader bh;
BankEntry be;
PackedTimbre pt;

FILE *fin;
badfile()
{
	fprintf(stderr, "File is not an AdLib Instrument Bank file\n");
	exit(1);
	fclose(fin);
}

main(argc,argv)
int argc;
char *argv[];
{
	int i, j;
	struct dat *d, *q;
	char *malloc();
	int maxidx;

	printcopy();
	if (argc != 2) {
		fprintf(stderr, "LISTBNK - This program lists the instruments within a .BNK file.\n");
		fprintf(stderr, "Usage:\n    listbnk bnkfile\nExample:\n    listbnk standard.bnk\n");
		fprintf(stderr, "Percussion instruments are labeled with a P followed by the\n");
		fprintf(stderr, "voice number (06 through 10) the instrument is assigned to.\n");
		exit(1);
	}
	if ((fin=fopen(argv[1], "rb")) == NULL) {
		fprintf(stderr, "Cannot open file: %s\n", argv[1]);
		exit(1);
	};
	if (fread(&bh, 1, sizeof(BankHeader), fin) != sizeof(BankHeader))
		badfile();
	if (strncmp(bh.sig, "ADLIB-", 6) != 0)
		badfile();
	if ((d=(struct dat *) malloc(bh.nrDefined * sizeof(struct dat))) == NULL) {
		fprintf(stderr, "Not enough memory.\n");
		exit(1);
	}
	if (fseek(fin, bh.offsetIndex, 0) != 0)
		badfile();
	q = d;
	maxidx = 0;
	for (i=0; i<bh.nrEntry ;i++) {
		if (fread(&be, 1, sizeof(BankEntry), fin) != sizeof(BankEntry))
			badfile();
		if (be.usedFlag) {
			strcpy(q->name, be.TimbreName);
			q->idx = be.nrReference;
			if (be.nrReference > maxidx)
				maxidx = be.nrReference;
			q++;
		}
	}
	if (fseek(fin, bh.offsetTimbre, 0) != 0)
		badfile();
	maxidx++;
	for (i=0; i<maxidx; i++) {
		if (fread(&pt, 1, sizeof(PackedTimbre), fin) != sizeof(PackedTimbre))
			badfile();
		for (j=0, q=d; j<bh.nrDefined; j++, q++)
			if (q->idx == i)
				break;
		if (j < bh.nrDefined) {
			q->pmode = pt.mode;
			q->voicenum = pt.percVoice;
		}
	}
	printf("\nBank file %s contains %d instruments\n\n", argv[1], bh.nrDefined);
	for (i=0, q=d; i<bh.nrDefined; i++, q++) {
		if (q->pmode)
			printf("  P%02d-%-8s", q->voicenum, q->name);
		else
			printf("      %-8s", q->name);
		if ((i+1)%5 == 0)
			printf("\n");
	}
	if (i%5 != 0)
		printf("\n");
	fclose(fin);
}
printcopy()
{
	static char notice[] = "Bankfile Listing Utility  V1.0   A. A. Kapauan 1991";
	fprintf(stderr, "\n%s\n\n", notice);
}

