/***************************************************************************
*       NAME:  IWPATCH.C $Revision: 1.19 $
**      COPYRIGHT:
**      "Copyright (c) 1994,1995 by e-Tek Labs"
**
**       "This software is furnished under a license and may be used,
**       copied, or disclosed only in accordance with the terms of such
**       license and with the inclusion of the above copyright notice.
**       This software or any other copies thereof may not be provided or
**       otherwise made available to any other person. No title to and
**       ownership of the software is hereby transfered."
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <io.h>
#include <string.h>
#include <alloc.h>
#include <fcntl.h>
#include "sbosdata.h"
#include "sbosdefs.h"
#include "stuff.h"
#include "iwpatch.h"
#include "utillib.h"
#include "iwscale.h"

void CopyData(void far *,unsigned char , unsigned long , unsigned int);
int AllocSpace(unsigned long ,unsigned long *);
extern FFF_INFO fff_info[10];

int current_instrument = 0;
CHUNK_HDR *fff_data;
char *dat_path;
unsigned int fff_size;
IW_PATCH *patch_ptr;
IW_LAYER *layer_ptr;
unsigned long layer_size;
IW_WAVE *wave_ptr;
IW_DATA *data_ptr;
IW_ENVP *envp_ptr;
IW_PROGRAM *prog_ptr;
unsigned long prog_size;
extern int listing;
extern int num_fffs;

typedef struct {
    int type;
    CHUNK_HDR header;
} CHUNK_TYPE;

typedef struct {
    unsigned long wave_offset;
    unsigned long wave_size;
    unsigned long dram_loc;
    unsigned int wave_num;
} SAMPLE_DEF;

SAMPLE_DEF *samples;
int num_samples;

#define UNKNOWN_HDR    0
#define FILE_HDR    1
#define PATCH_HDR    2
#define PROG_HDR    3
#define LAYER_HDR    4
#define WAVE_HDR    5
#define TEXT_HDR    6
#define DATA_HDR    7
#define ENVP_HDR    8
#define PTED_HDR    9

CHUNK_TYPE what_chunk[9]    = { 
        {FILE_HDR,   'F', 'F', 'F', 'F' , 0L},
        {PATCH_HDR,  'P', 'T', 'C', 'H' , 0L },
        {PROG_HDR,   'P', 'R', 'O', 'G' , 0L },
        {LAYER_HDR,  'L', 'A', 'Y', 'R' , 0L },
        {WAVE_HDR,   'W', 'A', 'V', 'E' , 0L },
        {TEXT_HDR,   'T', 'E', 'X', 'T' , 0L },
        {DATA_HDR,   'D', 'A', 'T', 'A' , 0L },
        {ENVP_HDR,   'E', 'N', 'V', 'P' , 0L },
        {PTED_HDR,   'P', 'T', 'E', 'D' , 0L },
};

extern WAVE_INFO *wave_info;
extern WAVE_DATA *wave_data;
extern SYN_ENVELOPE *mpu_info;
extern MAPS map1,map2;
extern SBOS_LIB_HEADER lib_header;
extern int current_wave;

int Normalize(int *);

/****************************************************************************

FUNCTION DEFINITION:
chunk_type -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
int chunk_type(CHUNK_HDR *chunk)
{
int i;

for (i=0;i<9;i++)
    {
    if (strncmp(chunk->tag,what_chunk[i].header.tag,4) == 0)
        return(what_chunk[i].type);
    }
return(UNKNOWN_HDR);
}

/****************************************************************************

FUNCTION DEFINITION:
find_patch -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
int find_patch(unsigned char pnum,unsigned char bnum)
{
char *prog_chunk;
char *ptch_chunk;
int i;

// Look thru ALL FFF files for the inst and bank ....

// Set the data_path if found ....
// Set the fff_data if found ....
// Set the fff_size if found ....

for (i=0;i<10;i++)
	{
	if (fff_info[i].fff_data == NULL)
		break;
	fff_data = fff_info[i].fff_data;
	fff_size = fff_info[i].fff_size;
	dat_path = fff_info[i].fff_path;

// Find the program chunks for this fff file ...
    prog_chunk = (char *)fff_data;    /* start at beginning of data .... */

    while(TRUE)
        {
        // quit if past end of file ...
        if (prog_chunk >= ((char*)fff_data+fff_size))
            break;
        if (chunk_type((CHUNK_HDR *)prog_chunk) == PROG_HDR)
            {
            // OK. we found a program chunk. Now find is patch info
            // and see if its for this program number
            prog_size = ((CHUNK_HDR *)prog_chunk)->length;
            prog_ptr = (IW_PROGRAM *)(prog_chunk+sizeof(CHUNK_HDR));
            // point to first chunk PAST program chunk
            ptch_chunk = prog_chunk+sizeof(IW_PROGRAM)+sizeof(CHUNK_HDR);
            while(TRUE)
                {
                // Not past this chunk please ....
                if (ptch_chunk >= (prog_chunk+prog_size))
                    break;
                if (chunk_type((CHUNK_HDR *)ptch_chunk) == PATCH_HDR)
                    {
                    // OK. got the patch header. Is it the right one ??
                    patch_ptr = (IW_PATCH *)(ptch_chunk+sizeof(CHUNK_HDR));
                    if ((patch_ptr->program == pnum)
                       && (patch_ptr->bank == bnum))
						{
                        return(1);
						}
                    break;    // bump to next program chunk
                    }
                // not a patch chunk  keep going
                ptch_chunk = ptch_chunk+((CHUNK_HDR *)ptch_chunk)->length
                                    +sizeof(CHUNK_HDR);
                }
            }
        // not a prog chunk or wrong program num, keep going
        prog_chunk = prog_chunk+((CHUNK_HDR *)prog_chunk)->length
                                    +sizeof(CHUNK_HDR);
        }
	}
patch_ptr = NULL;
return(0);
}

/****************************************************************************

FUNCTION DEFINITION:
find_layer -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
int find_layer(short lnum)
{
IW_LAYER *ptr;
char *layer_chunk;

// Assumes that patch pointer is already pointing to correct patch
// Now find the n-th layer
layer_chunk = ((char *)patch_ptr)+sizeof(IW_PATCH);

// If layer num is more than this patch has, force layer num to 0 ....
if (lnum > patch_ptr->nlayers)
    lnum = 0;

while (TRUE)
    {
    // Not past this prog chunk please ....
    if (layer_chunk >= ((char *)prog_ptr+prog_size))
        {
        layer_ptr = NULL;
        layer_size = 0;
        return(0);
        }
    // Now count down layers
    if (chunk_type((CHUNK_HDR *)layer_chunk) == LAYER_HDR)
        {
        // OK. got the layer header. Is it the right one ??
        layer_ptr = (IW_LAYER *)(layer_chunk+sizeof(CHUNK_HDR));
        layer_size = ((CHUNK_HDR *)layer_chunk)->length;
        if (lnum == 0)
            return(1);
        lnum--;
        }
    // not a layer chunk  keep going
    layer_chunk = layer_chunk+((CHUNK_HDR *)layer_chunk)->length+
                            sizeof(CHUNK_HDR);
    }
}

/****************************************************************************

FUNCTION DEFINITION:
find_wave -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
int find_wave(int wnum)
{
IW_WAVE *ptr;
char *wave_chunk;

// Assumes that layer pointer is already pointing to correct layer
// Now find the n-th wave
wave_chunk = ((char *)layer_ptr)+sizeof(IW_LAYER);

// If wave num is more than this layer has, force wave num to 0 ....
if (wnum > layer_ptr->nwaves)
    wnum = 0;

while (TRUE)
    {
    // Not past this prog chunk please ....
    if (wave_chunk >= ((char *)prog_ptr+prog_size))
        {
        wave_ptr = NULL;
        return(0);
        }
    // Now count down wave
    if (chunk_type((CHUNK_HDR *)wave_chunk) == WAVE_HDR)
        {
        // OK. got the wave header. Is it the right one ??
        wave_ptr = (IW_WAVE *)(wave_chunk+sizeof(CHUNK_HDR));
        if (wnum == 0)
            return(1);
        wnum--;
        }
    // not a wave chunk  keep going (should never happen)
    wave_chunk = wave_chunk+((CHUNK_HDR *)wave_chunk)->length+
                            sizeof(CHUNK_HDR);
    }
}

/****************************************************************************

FUNCTION DEFINITION:
find_envp -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
int find_envp(void RFAR *id)
{
char *chunk;
// Find the envelope for this id ...
    chunk = (char *)fff_data;    /* start at beginning of data .... */

    while(TRUE)
        {
        if (chunk >= ((char*)fff_data+fff_size))
            {
            envp_ptr = NULL;
            return(0);
            }
        if (chunk_type((CHUNK_HDR *)chunk) == ENVP_HDR)
            {
            envp_ptr = (IW_ENVP *)(chunk+sizeof(CHUNK_HDR));
            if (envp_ptr->id.p == id)
                return(1);
            }
        chunk = chunk+((CHUNK_HDR *)chunk)->length+sizeof(CHUNK_HDR);
        }
}

/****************************************************************************

FUNCTION DEFINITION:
find_data -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
int find_data(void RFAR *id)
{
char *chunk;
// Find the data file for this patch ...
    chunk = (char *)fff_data;    /* start at beginning of data .... */

    while(TRUE)
        {
        if (chunk >= ((char*)fff_data+fff_size))
            {
            data_ptr = NULL;
            return(0);
            }
        if (chunk_type((CHUNK_HDR *)chunk) == DATA_HDR)
            {
            data_ptr = (IW_DATA *)(chunk+sizeof(CHUNK_HDR));
            if (data_ptr->id.p == id)
                return(1);
            }
        chunk = chunk+((CHUNK_HDR *)chunk)->length+sizeof(CHUNK_HDR);
        }
}

/****************************************************************************

FUNCTION DEFINITION:
loadFFFs -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void LoadFFFs()
{
FILE *fff_fp;
char *fff_file;
int val;
CHUNK_HDR tchunk;
int done;
int ctype;
int i,w;

samples = malloc(1500*sizeof(SAMPLE_DEF));
if (samples == NULL)
    {    
    printf("Unable to alloc sample def. structs\n");
    return;
    }
    
// Now Load each one on line and setup up its struct ...

for (i=0;i<num_fffs;i++)
	{
	if (access(fff_info[i].fff_file,0) != 0)
		{
		break;
		}

// OK lets open up the FFF file and start reading the data
	fff_fp = fopen(fff_info[i].fff_file, "rb");
	if (fff_fp == NULL) 
		{
		printf("Can't find file %s.\n",fff_info[i].fff_file);
		return;
		}

// Eat the FFFF first
	val = fread(&tchunk,sizeof(CHUNK_HDR),1,fff_fp);
	if (val == 1)
		{
		if (strncmp(tchunk.tag,"FFFF",4) == 0)
			{
// OK. Let's malloc the memory for the FFF data and load it ...
			fff_info[i].fff_data = malloc((unsigned int)tchunk.length);
			if (fff_info[i].fff_data != NULL)
				{
				val = fread(fff_info[i].fff_data,(unsigned int)tchunk.length,1,fff_fp);
				fff_info[i].fff_size = (unsigned int)tchunk.length;
				if (val == 1)
					{
#ifdef NEVER
					for (i=0;i<255;i++)
						{
						if(find_patch(i),0)
							{
							printf("Found %d %p layers = %d\n",i,
												patch_ptr,patch_ptr->nlayers);
							if(find_layer(patch_ptr->nlayers-1))
								{
								printf("\tFound layer. Waves = %d\n",
												layer_ptr->nwaves);
								for (w=0;w<layer_ptr->nwaves;w++)
									{
									if (find_wave(w))
										{
										printf("\t\tFound wave %d\n",w);
										if (find_data(wave_ptr->data_id.p))
											printf("\t\t\tResides in %s\n",
													data_ptr->filename);
										else
											printf("Data file not found\n");
										}
									else
										{
										printf("\t\tWave not found(%d)\n",w);
										}
									}
								}
							else
								printf("Layer not found\n");
							}
						else
							printf("Not Found %d %p\n",i,patch_ptr);
						}
#endif
					}
				else
					printf("Bad FFF load\n");
				}
			else
				printf("Couldn't malloc RAM for FFF file\n");
			}
		else
			printf("Doesn't start with FFFF chunk\n");
		}
	else
		printf("Couldn't read inital chunk header\n");
	fclose(fff_fp);
	}
	if (i != num_fffs)
		{
		printf("Couldn't find all the FFF files.(%s)\n",fff_info[i].fff_file);
		exit(-1);
		}
}

/****************************************************************************

FUNCTION DEFINITION:
UnloadFFFs -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void UnloadFFFs()
{
int i;

free(samples);

for (i=0;i<10;i++)
	{
	if (fff_info[i].fff_data != NULL)
		free(fff_info[i].fff_data);
	}
}

/****************************************************************************

FUNCTION DEFINITION:
copy_envp -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void copy_envp(void)
{
int num_envp;
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 = (IW_ENVP_RECORD *)((unsigned char *)envp_ptr + sizeof(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 = (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(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++;
            }
// Don't use mode, zero it out ...
		mpu_info[current_wave].mode = 0;

// 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;
			}

}

/****************************************************************************

FUNCTION DEFINITION:
load_patch -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
int load_patch( char *patch_line,int patch_type,int size)
{
unsigned int inst_num;
unsigned int map_val;
unsigned int k512,k1024;
unsigned int convert;
char filename[20];
unsigned int layer_num;
int wave_num;
unsigned long dram_loc,temp_dram_loc;
unsigned int val;
unsigned char cval;
unsigned long temp_long;
unsigned char tmode;
unsigned char *data_buff;
unsigned long total_size;
unsigned int read_size;
unsigned int *inptr;
int fd;
char patch_file[128];
int X, YYY, ZZZZ, numberOfShiftBits, b;
int originalSample;
int i;
int inst_base;
long wavesize;
long wavestart;
long loopstart;
long loopend;
unsigned char format;
unsigned char endfrac;
long high_freq;
int snum,copy;
unsigned char bank_num;

    sscanf(patch_line,"%d, %d, %d, %d, %d, %s\n",
                    &inst_num,&k512,&k1024,&convert,&layer_num,filename);

    switch(size)
        {
        case 512:
            map_val = k512;
            break;
        case 1024:
            map_val = k1024;
            break;
        }
    switch(patch_type)
        {
        case TYPE_BASIC:
            map1.basic_map[lib_header.num_basic++] = map_val;
			bank_num = SINES_BANK;
            break;
        case TYPE_MELODIC:
            map1.melodic_map[lib_header.num_melodics++] = map_val;
			bank_num = 0;
            break;
        case TYPE_PERC:
            map1.perc_map[lib_header.num_percs++] = map_val;
			bank_num = 0;
            break;
        case TYPE_EFFECT:
            map1.effect_map[lib_header.num_effects++] = map_val;
			bank_num = 0;
            break;
        }

// This is a mapped instrument, don't try and load the patch ....

    if (inst_num != map_val)
        {
        return(0);
        }

    switch(patch_type)
        {
        case TYPE_BASIC:
            map2.basic_map[lib_header.num_basic-1] = 
                            current_wave-lib_header.patch_info.start_basic;
            inst_base = 251;
            break;
        case TYPE_MELODIC:
            map2.melodic_map[lib_header.num_melodics-1] = 
                            current_wave-lib_header.patch_info.start_melodics;
            inst_base = 0;
            break;
        case TYPE_PERC:
            map2.perc_map[lib_header.num_percs-1] = 
                            current_wave-lib_header.patch_info.start_percs;
            inst_base = 128;
            break;
        case TYPE_EFFECT:
            map2.effect_map[lib_header.num_effects-1] = 
                            current_wave-lib_header.patch_info.start_effects;
            inst_base = 0;
            break;
        }

#define DATA_SIZE (20U*1024U)

    data_buff = malloc(DATA_SIZE);
    if (data_buff == NULL)
        {
        printf("Can't allocate DATA buffer\n");
        return(8);
        }

// First point to correct patch in FFF file
    if(!find_patch(inst_num+inst_base,bank_num))
        {
        }

// Now point to the right layer in the patch
    if(!find_layer(layer_num))
        {
        }

    for( wave_num= 0;wave_num < layer_ptr->nwaves;wave_num++)
        {
if (listing)
	{
    printf("=================================================\n");
    printf("instrument - %d\n",inst_num);
    printf("=================================================\n");
	}
        if (!find_wave(wave_num))
            {
            }
// OK. Open the data file and read in the data ....
        if (!(find_data(wave_ptr->data_id.p)))
            {
            }
        wavesize = wave_ptr->size;
        wavestart = wave_ptr->start;
        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 (listing)
    printf("wavestats - start = %06lX size = %d\n",wavestart,wavesize);
        sprintf(patch_file,"%s\\%s",dat_path,data_ptr->filename);
        fd = open(patch_file, O_RDONLY | O_BINARY);
        if (fd == -1)
            {
			printf("Can't find data file (%s)\n",patch_file);
			getch();
			exit(-1);
            }
// seek to beginning of sample ...
        lseek(fd,wavestart,0);
        if (!(format & IW_WAVE_FORMAT_8BIT))    // if 16 bit data ...
            {
            wavesize <<= 1;
            loopstart <<= 1;
            loopend <<= 1;
            }

        if (!(format & IW_WAVE_FORMAT_8BIT))    // if 16 bit data ...
            {
            if (convert == 1)    // Convert from 16 to 8
                {
                format |= IW_WAVE_FORMAT_8BIT;    // make it 8 bit
                }
            else if (convert == 2)    // Convert 16 to 8 mu-law 
                {
                // Must set IW mode bit for mu-law
                }
            }
        else
            convert = 0;

        total_size = wavesize;

        if (convert != 0)
            {
            wavesize >>= 1;        // Cut data size in half
            loopstart >>= 1;
            loopend >>= 1;
            }

        copy = FALSE;

        for(snum=0;snum<num_samples;snum++)
            {
            if ((samples[snum].wave_size == wavesize) && 
                (samples[snum].wave_offset == wavestart))
                {
                copy = TRUE;
                break;
                }
            }

        if (copy)
            {
            val = DRAM_OK;
            dram_loc = samples[snum].dram_loc;
if (listing)
    printf("cur (%d) copy of (%d)\n",current_wave,samples[snum].wave_num);
            }
        else
            {
            val = AllocSpace(wavesize,&dram_loc);
            samples[num_samples].wave_size = wavesize;
            samples[num_samples].wave_offset = wavestart;
            samples[num_samples].dram_loc = dram_loc;
            samples[num_samples].wave_num = current_wave;
            num_samples++;
            }

        temp_dram_loc = dram_loc;
        if (val != TRUE)
            {
            printf("Unable to fit %s -%ld- into Memory (%d)\n",patch_file,wavesize,val);
            getch();
            close(fd);
            free(data_buff);
            return(7);
            }
        
        while(TRUE)
            {
            if (total_size == 0)
                break;
            if (total_size >= DATA_SIZE)
                {
                total_size -= DATA_SIZE;
                read_size = DATA_SIZE;
                }
            else
                {
                read_size = total_size;
                total_size = 0;
                }

            val = read( fd, data_buff, read_size );
            if( val != read_size )
                {
                close( fd );        
                free(data_buff);
                return( 6 );                
                }
// Now see if we need to convert to 8 bit or mu-law
            inptr = (unsigned int *)data_buff;
            switch(convert)
                {
                case 0:
                    break;
                case 1:        // 16 to 8 bit
                    read_size >>= 1;
                    for(i=0;i<read_size;i++)
                        {
                        data_buff[i] = (inptr[i]) >> 8;
                        }
                    break;
                case 2:        // 16 mu-law to 8 bit
                    read_size >>= 1;
                    for(i=0;i<read_size;i++)
                        { // convert byte by byte
                        originalSample = inptr[i];
                        originalSample >>=2;
                        if (originalSample <= -8159)
                            data_buff[i] = 0x00;
                        else if( originalSample >= 8159)
                            data_buff[i] = 0x80;
                        else
                            {
                            X = (originalSample & 0x2000) >> 6;
                            if( originalSample & 0x2000) 
                                originalSample = -originalSample;
                            originalSample <<=2;
                            originalSample += 0x84;
                            numberOfShiftBits = Normalize(&originalSample);
                            ZZZZ = (originalSample & 0x3c00) >> 10;
                            YYY = (7- numberOfShiftBits) << 4;
                            data_buff[i] = X | YYY | ZZZZ;
                            data_buff[i] = ~data_buff[i];
                            }
                        }
                    break;
                }
            tmode = 0;
            if (!(format & IW_WAVE_FORMAT_8BIT))
                tmode |= 0x40;
            if (!(format & IW_WAVE_FORMAT_SIGNED))
                tmode |= 0x80;

            CopyData(data_buff,tmode,temp_dram_loc,read_size);
            temp_dram_loc+=read_size;
            }
        close(fd);

// Now fil in the envelope data for MPU401 emul
        if(!(find_envp(layer_ptr->venv.p)))
			{
			}
		copy_envp();
// Xlate data to my data structs here ....

        wave_info[current_wave].magic_num = wave_ptr->sample_ratio;

// save begin location
        temp_long = dram_loc << 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 
        if(!(find_envp(layer_ptr->venv.p)))
            {
            tmode |= 0x20;
            }
        else
            {
            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("patch - %s\n",patch_file);
    printf("wavenum - %d\n",current_wave);
    printf("begin = 0x%06lX\n",dram_loc);
    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 ....
        }    
// Force last wave to include all frequencies ....
    wave_data[current_wave-1].end_freq = 0xff;
    free(data_buff);
    return(0);
}

/****************************************************************************

FUNCTION DEFINITION:
get_sustain_bit -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
int get_sustain_bit( int patch_type, char *patch_line,int size,unsigned char *bit)
{
unsigned int inst_base;
unsigned int inst_num;
unsigned int layer_num;
char filename[30];

	size = size;	// for compiler warning (needed for MAX)

    sscanf(patch_line,"%d, %*d, %*d, %*d, %d, %s\n",
                &inst_num,&layer_num,filename);

    switch(patch_type)
        {
        case TYPE_MELODIC:
            inst_base = 0;
            break;
        case TYPE_PERC:
            inst_base = 128;
            break;
        }

    *bit = 1;        // In case its not found .....

// First point to correct patch in FFF file
    if(find_patch(inst_num+inst_base,0))
        {
// Now point to the right layer in the patch
        if(find_layer(0))
            {
            if(!(find_envp(layer_ptr->venv.p)))
                {
printf("\n******* Can't find envp id %p (%d)\n",
                    layer_ptr->venv.p,inst_num+inst_base);
                *bit = 1;        // For it to a sustaining instrument ....
                }
            else
                {
                if (envp_ptr->h.mode != IW_ENVELOPE_ONE_SHOT)
                    *bit = 1;
                else
                    *bit = 0;
                }
            }
        }
    else
if (listing)
        printf("\n****** Can't find patch %d\n",inst_num+inst_base);
    return(0);
}
