#include <conio.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <direct.h>
#include <math.h>
#include <sys/stat.h>

#include "iw.h"
#include "patch.h"
#include "list.h"
#include "rommaker.h"
#include "sbosdata.h"
#include "iwscale.h"

static struct header file_header = { { 'F', 'F', 'F', 'F' }, 0L };
static struct header sbos_header = { { 'S', 'B', 'O', 'S' }, 0L };

typedef struct {
	short level;
	short rate;
} ENV_DATA;

MAPS map1,map2;
WAVE_INFO *wave_info;
WAVE_DATA *wave_data;
SYN_ENVELOPE *mpu_info;
int current_wave;
int listing = 0;

#define MAX_BANKS	4
extern long split_location[MAX_BANKS];
extern long data_size[MAX_BANKS];
extern long data_start[MAX_BANKS];
extern struct list data_list;
extern struct data_node {
    long astart;
    long aend;
    long nstart;
    char fname[132];
    unsigned char flags;
};

int layers[256] = {0};

void
append_sbos_space(FILE *fp,char *rom_cfg_file)
{
    struct iwu_fast_patch *fpi;
    struct header tchunk;
	unsigned long sbos_len;
	unsigned int num_waves;
	int i;
    struct patch_lib *pl;
    struct iw_layer *lc;
	FILE *tfp;
	char layer_line[MAXPATH];
	char filename[MAXPATH];
	int inst_num;
	int layer_num;
	unsigned char *ptr;
	int val;
	int j;

// First calc the size of the structure ...

// Read in the layer info from the cfg file (sboslyrs.ini)
for (i=0;i<256;i++)
	layers[i] = 0;

tfp = fopen("sboslyrs.ini","r");
if (tfp == NULL)
	{
	printf("Can't open sbos layer info file (sboslyrs.ini)\n");
	exit(-1);
	}

while(1)
	{
    ptr = fgets(layer_line,MAXPATH,tfp);
	if (ptr == NULL)
		break;
    if (*ptr == '#')
        continue;
    val = sscanf(layer_line,"%d, %d, %s\n",
                    &inst_num,&layer_num,filename);
	if (val == 3)
		{
		layers[inst_num] = layer_num;
		printf("inst %d layer %d patch_file %s\n",inst_num,layer_num,filename);
		}
	else
		printf("Can't parse line (%s)",layer_line);
    }
fclose(tfp);

// All the id's have been re-written (not pointers anymore), so re-load
// FFF file ...
	rom_get_patch_config(rom_cfg_file);

	num_waves = 0;
	pl = plib;

// Don't actually NEED to count these. There are always 5 waves total ...
	for (i=0;i<5;i++)
		{
		// They are always in bank #SINES_BANK  and start at program  #250....
		fpi = iwu_find_patch(251+i, SINES_BANK, &pl);
		if (fpi != 0)
			{
			num_waves++;
			}
		else
			printf("Can't find sines (prog %d bank %d)\n",251+i,SINES_BANK);
		}

// Now find GM insts....
	for (i=0;i<128;i++)
		{
		fpi = iwu_find_patch(i, 0, &pl);
		if (fpi != 0)
			{
			lc=fpi->p->layers;
			if (layers[i] <= fpi->p->nlayers)
				for (j=0; j < layers[i]; j++, lc=lc->id.p)
					{
					printf("Inst #%d uses layer %d\n",i,layers[i]);
					}
			num_waves+= lc->nwaves;
			}
		else
			{
			// No patch found ....
			}
		}

	for (i=28;i<128;i++)
		{
		fpi = iwu_find_patch(i+128, 0, &pl);
		if (fpi != 0)
			{
			lc=fpi->p->layers;
			if (layers[i] <= fpi->p->nlayers)
				for (j=0; j < layers[i+128]; j++, lc=lc->id.p)
					{
					printf("Inst #%d uses layer %d\n",i,layers[i]);
					}
			num_waves+= lc->nwaves;
			}
		else
			{
			// No patch found ....
			}
		}
// OK. Now I know how many waves I will have, let's add up the space I need

sbos_len = sizeof(ROMSBOS); // header stuff ....
// Round it up to 32 byte boundary
sbos_len = ((sbos_len + 31L) & -32L);

sbos_len += (num_waves*sizeof(WAVE_DATA));	// wave_data array ....
// Round it up to 32 byte boundary
sbos_len = ((sbos_len + 31L) & -32L);

sbos_len += (num_waves * sizeof(WAVE_INFO)); // per wave information

// Round it up to 32 byte boundary
sbos_len = ((sbos_len + 31L) & -32L);

sbos_len += (num_waves * sizeof(SYN_ENVELOPE)); // per wave information

// Now write the FFFF header chunk
	tchunk = file_header;
	tchunk.length = sbos_len + sizeof(file_header);
	fwrite(&tchunk, sizeof(tchunk), 1, fp);

// Now add the SBOS header chunk
	tchunk = sbos_header;
	tchunk.length = sbos_len;
	fwrite(&tchunk, sizeof(tchunk), 1, fp);

	for (i=0;i<tchunk.length;i++)
		fputc(0, fp);
}
void
copy_envp(struct iw_envp *envp_ptr)
{
int num_envp;
struct iw_envp_record *env_rec;
short nattack,nrelease;
int envelope_num;
int ce;
unsigned char midrange;
int i;
ENV_DATA *env_points;

num_envp = envp_ptr->h.num_envelopes;

env_rec = (struct iw_envp_record *)((unsigned char *)envp_ptr + sizeof(struct iw_envp));

envelope_num = 0;

if (envp_ptr->h.index_type == IW_ENVELOPE_IDX_NONE)
	;
else
	{
   	if (envp_ptr->h.index_type == IW_ENVELOPE_IDX_VELOCITY)
		midrange=64;
	else if (envp_ptr->h.index_type == IW_ENVELOPE_IDX_FREQUENCY)
		midrange=64;

	// Find the 'middle' envelope ....
	for (i=0;i<num_envp;i++)
		{
		if (midrange <= env_rec->hirange)
			break;
// Point to NEXT envelope ....
envelope_num++;
		env_rec = (struct iw_envp_record*)((char *)(env_rec+1)+
					(env_rec->nattack+env_rec->nrelease)*2*sizeof(short));
		}
	}

// OK env_rec point to the envelope we want ...
	env_points = (ENV_DATA *)((char *)(env_rec) + sizeof(struct iw_envp_record));

		ce = 0;

		for (i=0;i<6;i++)
			{
			mpu_info[current_wave].rate[i] = 0x3f;
			mpu_info[current_wave].level[i] = 4<<4;
			}

// First copy the attacks ....
        for (i=0;i<env_rec->nattack;i++)
            {
            mpu_info[current_wave].rate[ce] = env_points[ce].rate;
            mpu_info[current_wave].level[ce] = (env_points[ce].level&0xff)<<4;
			ce++;
            }
// Account for sustain point too ....
        mpu_info[current_wave].nattacks = env_rec->nattack+1;

// Now copy the sustain stuff
        mpu_info[current_wave].rate[ce] = env_rec->sustain_rate;
        mpu_info[current_wave].level[ce] = env_rec->sustain_offset<<4;
        ce++;

// Now copy the release(s)
        for (i=0;i<env_rec->nrelease;i++)
            {
			if (ce == 5)
				ce--;
            mpu_info[current_wave].rate[ce] = env_points[ce].rate;
            mpu_info[current_wave].level[ce] = (env_points[ce].level&0xff)<<4;
			ce++;
			}
// Account for last release point too
        mpu_info[current_wave].nreleases = env_rec->nrelease+1;

// Copy the last release point ...
        mpu_info[current_wave].rate[ce] = env_rec->release_rate;
        mpu_info[current_wave].level[ce] = 4<<4;

		for (i=0;i<6;i++)
			{
			if (mpu_info[current_wave].level[i] < (4<<4))
		        mpu_info[current_wave].level[i] = 4<<4;
			}

}

void parse_patch(int program,int bank,struct patch_lib *pl)
{
struct iwu_fast_patch *fpi;
struct iw_layer *layer_ptr;
struct iw_envp *envp_ptr;
struct iw_wave RFAR *wave_ptr;
struct iw_data RFAR *dc;
int wave_num;
long wavesize;
long loopstart;
long loopend;
unsigned char format;
unsigned char endfrac;
long high_freq;
unsigned long temp_long;
unsigned int val;
unsigned char cval;
unsigned char tmode;
int i,j;
long was, wae;
struct node *dn, *dn1, *dn2;
struct data_node *dln, *dln1;
long previous_split1, previous_split2;


if (listing)
	{
	printf("=========================================================\n");
	printf("instrument - %d\n",program);
	}
fpi = iwu_find_patch(program, bank, &pl);
if (fpi != 0)	// skip if not found ....
	{
	// Find the right layer #
	layer_ptr=fpi->p->layers;
	if (layers[program] <= fpi->p->nlayers)
		for (j=0; j < layers[program]; j++, layer_ptr=layer_ptr->id.p)
			{
//			printf("Inst #%d uses layer %d\n",program,layers[program]);
			}

	wave_ptr = layer_ptr->waves;
	for (wave_num=0; wave_num < layer_ptr->nwaves; wave_num++, wave_ptr=wave_ptr->id.p)
		{

		if (current_wave == 366)
			asm nop;
// OK. Open the data file and read in the data ....
        wavesize = wave_ptr->size;
        loopstart = wave_ptr->loopstart>>4; // clip off fraction
        loopend = (wave_ptr->loopend>>4);     // clip off fraction
        endfrac = wave_ptr->loopend&0x0000000f;
        format = wave_ptr->format;

        if (!(format & IW_WAVE_FORMAT_8BIT))    // if 16 bit data ...
            {
            wavesize <<= 1;
            loopstart <<= 1;
            loopend <<= 1;
            }

// Now fill in the envelope data for MPU401 emul
		copy_envp(layer_ptr->venv.p);

// Xlate data to my data structs here ....

        wave_info[current_wave].magic_num = wave_ptr->sample_ratio;
	if (listing)
		{
	printf("=========================================================\n");
	    printf("wavenum - %d\n",current_wave);
	    printf("begin (prior) = 0x%06lX\n",wave_ptr->start);
		}

// save begin location
// Convert to ROM-type addresses ...
		/* fix up wave chunk and point to correct data chunk */
		for (dn = data_list.head; dn != 0; dn = dn->next) {
			dln = dn->data;
			was = wave_ptr->start;
			if (wave_ptr->format & IW_WAVE_FORMAT_8BIT) {
			wae = was + wave_ptr->size - 1;
			} else {
			wae = was + (wave_ptr->size<<1) - 1;
			}
			if (was >= dln->astart && wae <= dln->aend) {
			/* now find out which chip data is in */
			i = 0;
			previous_split2 = -1;
			while (!(was > previous_split2 && wae <= split_location[i])) {
				previous_split2 = split_location[i++];
			}
			wave_ptr->start = (wave_ptr->start - (previous_split2 + 1)) + (i * 4UL * 1024UL * 1024UL) + data_start[i];
// Now add in the ROM # into bits 22 and 23 ....
			wave_ptr->start |= ((long)i<<22L);
			break;
			}
		}
		temp_long = wave_ptr->start << 8;
		// add in end fraction (last 4 bits)
		temp_long |= endfrac;
		
		// Add in start multiplier
		cval = (((loopstart)/ (64L*1024L)) & 0x03);
		cval <<= 4;
		temp_long |= (long)cval;
		
		cval = (((loopend)/ (64L*1024L)) & 0x03);
		cval <<= 6;
        temp_long |= (long)cval;
        wave_info[current_wave].start_pos = temp_long;

        wave_info[current_wave].beg_offset=(loopstart)%(64L*1024L);
        wave_info[current_wave].end_offset=(loopend)%(64L*1024L);

        // Now set the mode bits for the driver (run-time use)
        tmode = 0;
        if (!(format & IW_WAVE_FORMAT_8BIT))
            tmode |= 0x01;        // Show 16 bit patch 

        if (format & IW_WAVE_FORMAT_LOOP)
            tmode |= 0x04;        // Show it loops

        if (format & IW_WAVE_FORMAT_BIDIR)
            tmode |= 0x08;        // Show it loops bidrectional

        if (!(format & IW_WAVE_FORMAT_FORWARD))
            tmode |= 0x10;        // Show it goes forward

// Put u-law patches here someday .....
// #define IW_WAVE_FORMAT_ULAW    BIT5

        // Turn this bit on of this patch is SUPPOSED to sustain
		envp_ptr = layer_ptr->venv.p;

        switch(envp_ptr->h.mode)
            {
            case IW_ENVELOPE_SUSTAIN:
                tmode |= 0x20;
                break;
            case IW_ENVELOPE_ONE_SHOT:
                break;
            case IW_ENVELOPE_NO_SUSTAIN:
                tmode |= 0x40;
                break;
            }

        // Show driver this has a sampled attack
        if ((loopstart) != 0)
            tmode |= 0x80;

        wave_info[current_wave].mode = tmode;

        wave_info[current_wave].atten = layer_ptr->attenuation+
										wave_ptr->attenuation;

        wave_info[current_wave].freq_scale = layer_ptr->freq_scale;
        wave_info[current_wave].freq_center = layer_ptr->freq_center;

        /* Since the end frequency should top out at about 8K, we can fit */
        /* what we need into a character ... */

        // xlate from note to frequency ....
        high_freq = iwl_scale_table[wave_ptr->high_note];
        val =(unsigned int)(high_freq / 1024L);
        val = val >> 5;
        if (val > 255)
            val = 255;
        wave_data[current_wave].end_freq = val;

if (listing)
    {
    printf("begin (ROM) = 0x%06lX\n",wave_ptr->start);
    printf("size = %ld (%ld)\n",wave_ptr->size,wavesize);
    printf("start = 0x%lX (%lX)\n",wave_ptr->loopstart,loopstart);
    printf("end = 0x%lX (%lX)\n",wave_ptr->loopend,loopend);
    printf("high note = %d\n",wave_ptr->high_note);
    printf("magic num = %ld\n",wave_info[current_wave].magic_num);
    printf("freq scaling = %d\n",layer_ptr->freq_scale);
    printf("freq center = %d\n",layer_ptr->freq_center);
    printf("new_start = 0x%lx\n",wave_info[current_wave].start_pos);
    printf("beg_offset = 0x%x\n",wave_info[current_wave].beg_offset);
    printf("end_offset = 0x%x\n",wave_info[current_wave].end_offset);
    printf("orig mode = 0x%x\n",wave_ptr->format);
    printf("mode = 0x%x\n",wave_info[current_wave].mode);
    printf("wave atten = %d\n",wave_ptr->attenuation);
    printf("layer atten = %d\n",layer_ptr->attenuation);
    printf("total atten = %d\n",wave_info[current_wave].atten);
    printf("end_freq = 0x%x (%d-%d)\n",wave_data[current_wave].end_freq,
                wave_ptr->low_note,wave_ptr->high_note);
	printf("nattacks = %d\n",mpu_info[current_wave].nattacks);
	printf("nreleases = %d\n",mpu_info[current_wave].nreleases);
    printf("rates: ");
    for (i=0;i<6;i++)
        printf("(%0x) ",mpu_info[current_wave].rate[i]);
    printf("\n");
    printf("offsets: ");
    for (i=0;i<6;i++)
        printf("(%0x) ",mpu_info[current_wave].level[i]);
    printf("\n");
    }
        current_wave++;        // so load goes to next wave struct ....
        }
	}
}


void write_sbos_data(long filepos,void *buff, struct patch_lib *pl)
{
ROMSBOS *romsbos;
char *ptr;
struct iwu_fast_patch *fpi;
struct header tchunk;
unsigned long sbos_len;
unsigned int num_waves;
int i,j;
struct iw_layer *lc;
struct iw_envp *ec;
long pos;

romsbos = (ROMSBOS *)buff;

for (i=0;i<MAX_BASIC;i++)
    {
    romsbos->sboslib.lib_map.basic_map[i] = 0;
    map1.basic_map[i] = 0;
    map2.basic_map[i] = 0;
    }
for (i=0;i<MAX_MELODICS;i++)
    {
    romsbos->sboslib.lib_map.melodic_map[i] = 0;
    map1.melodic_map[i] = 0;
    map2.melodic_map[i] = 0;
    }
for (i=0;i<MAX_PERCS;i++)
    {
    romsbos->sboslib.lib_map.perc_map[i] = 0;
    map1.perc_map[i] = 0;
    map2.perc_map[i] = 0;
    }
for (i=0;i<MAX_EFFECTS;i++)
    {
    romsbos->sboslib.lib_map.effect_map[i] = 0;
    map1.effect_map[i] = 0;
    map2.effect_map[i] = 0;
    }

	num_waves = 0;

romsbos->sboslib.patch_info.start_basic = 0;
romsbos->sboslib.patch_info.start_melodics = 5;
romsbos->sboslib.patch_info.start_effects = 0;


// Don't actually NEED to count these. There are always 5 waves total ...
	for (i=0;i<5;i++)
		{
   	    map1.basic_map[i] = i;
        map2.basic_map[i] = num_waves;
		// They are always in bank #SINES_BANK  and start at program  #250....
		fpi = iwu_find_patch(251+i, SINES_BANK, &pl);
		if (fpi != 0)
			{
			num_waves++;
			}
		else
			printf("Can't find sines (prog %d bank %d)\n",251+i,SINES_BANK);
		}

// Now find melodic insts....
	for (i=0;i<MAX_MELODICS;i++)
		{
   	    map1.melodic_map[i] = i;
   	    map2.melodic_map[i] = num_waves-romsbos->sboslib.patch_info.start_melodics;
		fpi = iwu_find_patch(i, 0, &pl);
		if (fpi != 0)
			{
			lc=fpi->p->layers;
			if (layers[i] <= fpi->p->nlayers)
				for (j=0; j < layers[i]; j++, lc=lc->id.p)
					{
//					printf("Inst #%d uses layer %d\n",i,layers[i]);
					}
			num_waves+= lc->nwaves;
			}
		else
			{
			// No patch found ....
			}
		}
// num_waves = where percs start. save it for later ....
romsbos->sboslib.patch_info.start_percs = num_waves;

	for (i=0;i<28;i++)
		{
   	    map1.perc_map[i] = 35;	// might as well map to something ....
		}

// Now count up valid percs also.
	for (i=28;i<MAX_PERCS;i++)
		{
   	    map1.perc_map[i] = i;
   	    map2.perc_map[i] = num_waves-romsbos->sboslib.patch_info.start_percs;
		fpi = iwu_find_patch(i+128, 0, &pl);
		if (fpi != 0)
			{
			lc=fpi->p->layers;
			if (layers[i] <= fpi->p->nlayers)
				for (j=0; j < layers[i+128]; j++, lc=lc->id.p)
					{
//					printf("Inst #%d uses layer %d\n",i,layers[i]);
					}
			num_waves+= lc->nwaves;
			}
		else
			{
			// No patch found ....
			}
		}

romsbos->sboslib.major = 0;
romsbos->sboslib.minor1 = 0;
romsbos->sboslib.minor2 = 0;
romsbos->sboslib.num_waves = num_waves;
romsbos->sboslib.num_basic = MAX_BASIC;
romsbos->sboslib.num_melodics = MAX_MELODICS;
romsbos->sboslib.num_percs = MAX_PERCS;
romsbos->sboslib.num_effects = 0;

// Get these from the FFF file ...
//    unsigned char sustain[256];   // default sustains for picker
for (i=0;i<256;i++)
	{
	fpi = iwu_find_patch(i, 0, &pl);
	if (fpi != 0)
		{
		lc=fpi->p->layers;
		if (layers[i] <= fpi->p->nlayers)
			for (j=0; j < layers[i]; j++, lc=lc->id.p)
				{
//				printf("Inst #%d uses layer %d\n",i,layers[i]);
				}

		ec = lc->venv.p;
        if (ec->h.mode != IW_ENVELOPE_ONE_SHOT)
			{
            romsbos->sboslib.sustain[i] = 1;
			}
		else
			{
			romsbos->sboslib.sustain[i] = 0;	// init it to no sustain
			}
		}
	}

//Now adjust the final maps (inst -> wavenum)
for (i=0;i<romsbos->sboslib.num_basic;i++)
    romsbos->sboslib.lib_map.basic_map[i] = map2.basic_map[map1.basic_map[i]];

for (i=0;i<romsbos->sboslib.num_melodics;i++)
    romsbos->sboslib.lib_map.melodic_map[i] = map2.melodic_map[map1.melodic_map[i]];

for (i=0;i<romsbos->sboslib.num_percs;i++)
    romsbos->sboslib.lib_map.perc_map[i] = map2.perc_map[map1.perc_map[i]];

for (i=0;i<romsbos->sboslib.num_effects;i++)
    romsbos->sboslib.lib_map.effect_map[i] = map2.effect_map[map1.effect_map[i]];


romsbos->sboslib.dram_info.dram_begin = 0L;
romsbos->sboslib.dram_info.dram_stopped_voice = 32L;
romsbos->sboslib.dram_info.dram_temp_buff = romsbos->sboslib.dram_info.dram_stopped_voice + 64L;
romsbos->sboslib.dram_info.dram_perc_map = romsbos->sboslib.dram_info.dram_temp_buff + 64L;
romsbos->sboslib.dram_info.dram_wave_info = romsbos->sboslib.dram_info.dram_perc_map + 256L;
romsbos->sboslib.dram_info.dram_mpu_info = romsbos->sboslib.dram_info.dram_wave_info +
					(num_waves*sizeof(WAVE_INFO));

for (i=0;i<32;i++)
	romsbos->spare[i] = 0;

for (i=0;i<64;i++)
	romsbos->stopped[i] = 0x55;

for (i=0;i<32;i++)
	romsbos->tempbuff[i] = 0;

// Percs that don't exist ....
for (i=0;i<28;i++)
	romsbos->perc_map[i] = 35;

for (i=28;i<MAX_PERCS;i++)
	romsbos->perc_map[i] = i;

// OK. Everything but the wave info, wave_data and mpu_info are done ....

// These will point into the buffer passed in. There should be room as
// long as the FFF file hasn't been corrupted .....

// Find the next 32 byte boundary in the output file
pos = ((filepos+(long)sizeof(ROMSBOS)+31L) & -32L);
// subtract out the file position ...
ptr = (char *)((long)buff + (pos-filepos));
wave_data = (WAVE_DATA *)(ptr);

pos = pos+(sizeof(WAVE_DATA)*num_waves);
pos = (pos+31L) & -32L;
ptr = (char *)((long)buff + (pos-filepos));
wave_info = (WAVE_INFO *)(ptr);

pos = pos+(sizeof(WAVE_INFO)*num_waves);
pos = (pos+31L) & -32L;
ptr = (char *)((long)buff + (pos-filepos));
mpu_info = (SYN_ENVELOPE *)(ptr);

// OK. Now do what the library builder does to fill in these structs ....

// Parse BASIC ones first
	current_wave = 0;

	for (i=0;i<5;i++)
		{
		// They are always in bank #SINES_BANK  and start at program  #250....
		parse_patch(251+i, SINES_BANK, pl);
		}

// Now Parse GM melodic insts....
	for (i=0;i<MAX_MELODICS;i++)
		{
		parse_patch(i, 0, pl);
		}

// Now Parse GM perc insts....
	for (i=128+28;i<256;i++)
		{
		parse_patch(i, 0, pl);
		}
}
