/***************************************************************************
*       NAME:  BLDLIB.C $Revision: 1.18 $
**      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."
****************************************************************************/
#define DEBUG

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
#include <alloc.h>
#include <dos.h>
#include <dir.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>
#include <conio.h>

#define PATCH_HEADER_SIZE    8

/*****************************************************************************
*
* Miscellaneous defines for offsets into DRAM where some data structures
* will reside
*
*****************************************************************************/
#define DRAM_BEGIN 0L
// This buffer is for pointing each voice to when its not running
#define DRAM_STOPPED_VOICE DRAM_BEGIN+32L
// This is a temporary buffer that may be used for anything
#define DRAM_TEMP_BUFF DRAM_STOPPED_VOICE+32L
// Percussion mapping
#define DRAM_PERC_MAP DRAM_TEMP_BUFF+32L
// This is where the wave info data starts
#define DRAM_WAVE_INFO DRAM_PERC_MAP+(128L*2)

#include "version.h"
#include "sbosdefs.h"
#include "utillib.h"
#include "dma.h"

#include "stuff.h"
#include "iwpatch.h"
char *ini_file;
FFF_INFO fff_info[10];
int num_fffs = 0;

#include "sbosdata.h"
#include "patch.h"

extern int num_samples;
void LoadFFFs(void);
void UnloadFFFs(void);
int    get_sustain_bit( int , char *,int ,unsigned char *);
int    load_patch( char *,int ,int );

WAVE_INFO *wave_info;
WAVE_DATA *wave_data;
SYN_ENVELOPE *mpu_info;
SBOS_LIB_HEADER lib_header;
PORT_STRUC ports;
int current_wave;
int listing = FALSE;
MAPS map1,map2;
int lib_fd;
unsigned long end_dram;

char *mls_path;

unsigned char mixer_mask = 0x09; // Disable line-in, mic-in, enable line-out

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

FUNCTION DEFINITION:
control_break - New control break handler

RETURNS: 0

*/
int control_break( )
{
    return( 0 );
}

int
AllocSpace(unsigned long size,unsigned long *location)
{
/* Round size up to next (3)2 byte boundary */
size += 1;
size &= -2L;
if (end_dram <= size)
    {
    return(FALSE);
    }
else
    {
    end_dram -= size;
    *location = end_dram;
    }
return(TRUE);
}

void CopyData(void far *data_ptr,unsigned char mode,
              unsigned long dram_loc, unsigned int size)
{
unsigned char *bptr;
unsigned int *wptr;
unsigned int i;
unsigned int new_size;

lseek(lib_fd,dram_loc,0);    // seek to proper place within image file ...

if (mode & 0x40)
    new_size = size>>1;
else
    new_size = size;

bptr = (unsigned char *)data_ptr;
wptr = (unsigned int *)data_ptr;

// Now xlate data from input buffer to output data format (8-bit/unsigned)
if ((mode & 0x80))    // do unsigned conversion ??
    {
    for (i=0;i<new_size;i++)
        {
        if (mode & 0x40)    // Yes, is it 16 bit
            *wptr++ ^= 0x8000;
        else                // Yes, its 8 bit
            *bptr++ ^= 0x80;
        }
    }


if (write(lib_fd,data_ptr,size) != size)
    printf("Error writing data to image file (%d)\n",errno);
}

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

FUNCTION DEFINITION:
display_header -  Prints out message header before building libraries

*/
void display_header(int size)
{
clrscr();

printf("\n                   Copyright 1995 \n");
printf("               Advanced Micro Devices\n");
printf("      Building IWSBOS %dK patch library\n\n",size);
}

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

FUNCTION DEFINITION:
Normalize - Normalization routine for ulaw conversion

RETURNS: Normalized value

*/
int Normalize(int *value)
{
    int numShiftBits = 0;
    int msb, nextmsb;

    msb = (*value & 0x8000) >> 15;
    nextmsb = (*value & 0x4000) >> 15;
    while( msb == nextmsb )
        {
        *value <<= 1;
        numShiftBits ++;
        msb = (*value & 0x8000) >> 14;
        nextmsb = (*value & 0x4000) >> 14;
        }
    return(numShiftBits);
}

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

FUNCTION DEFINITION:
pick_slowest - 

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
unsigned char pick_slowest(PATCHDATA *pdata)
{
int i,j;
unsigned int high=0;
unsigned char rdata;
unsigned char data;
unsigned int value;

//vjf what does this do???
for (i=0;i<4;i++)
    {
    data = pdata->envelope_rate[i+2];
    j = data>>6;
    value = 1;
    for (;j!=0;j--)
        value *= 8;
    value += (0x3f - (data&0x3f));
    if (value > high)
        {
        high = value;
        rdata = data;
        }
    }
return(rdata);
}

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

FUNCTION DEFINITION:
Build_Basic -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void Build_Basic(FILE *fp,int size)
{
char patch_line[MAXPATH];
char *ptr;
int i;

lib_header.patch_info.start_basic = current_wave;

for (i=0;i<MAX_BASIC;i++)
    {
    lib_header.lib_map.basic_map[i] = 0;
    map1.basic_map[i] = 0;
    map2.basic_map[i] = 0;
    }

printf("Processing Basic patches\n");

rewind(fp);

while(TRUE)
    {
    ptr = fgets(patch_line,MAXPATH,fp);
    if (ptr == NULL)
        break;
    if (strcmp(ptr,"[Basic Patches]\n") == 0)
        {
        break;
        }
    }

if (ptr != NULL)
    {
    while(TRUE)
        {
        ptr = fgets(patch_line,MAXPATH,fp);
        if (*ptr == '\n' ||  ptr == NULL || *ptr == '[')
            break;
        if (*ptr == '#')
            continue;
#ifdef DEBUG
         printf("%s",patch_line);
#endif
        load_patch(patch_line,TYPE_BASIC,size);
        }
    }
}

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

FUNCTION DEFINITION:
Build_Melodics - 

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void Build_Melodics(FILE *fp,int size)
{
char patch_line[MAXPATH];
char *ptr;
int i;

lib_header.patch_info.start_melodics = current_wave;

for (i=0;i<MAX_MELODICS;i++)
    {
    lib_header.lib_map.melodic_map[i] = 0;
    map1.melodic_map[i] = 0;
    map2.melodic_map[i] = 0;
    }

printf("Processing Melodic patches\n");

rewind(fp);

while(TRUE)
    {
    ptr = fgets(patch_line,MAXPATH,fp);
    if (ptr == NULL)
        break;
    if (strcmp(ptr,"[Melodic Patches]\n") == 0)
        {
        break;
        }
    }

if (ptr != NULL)
    {
    while(TRUE)
        {
        ptr = fgets(patch_line,MAXPATH,fp);
        if (*ptr == '\n' ||  ptr == NULL || *ptr == '[')
            break;
        if (*ptr == '#')
            continue;
#ifdef DEBUG
         printf("%s",patch_line);
#endif
        load_patch(patch_line,TYPE_MELODIC,size);
        }
    }
}

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

FUNCTION DEFINITION:
Build_Percs -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void Build_Percs(FILE *fp,int size)
{
char patch_line[MAXPATH];
char *ptr;
int i;

lib_header.patch_info.start_percs = current_wave;

for (i=0;i<MAX_PERCS;i++)
    {
    lib_header.lib_map.perc_map[i] = 0;
    map1.perc_map[i] = 0;
    map2.perc_map[i] = 0;
    }

rewind(fp);

printf("Processing Percussion patches\n");

while(TRUE)
    {
    ptr = fgets(patch_line,MAXPATH,fp);
    if (ptr == NULL)
        break;
    if (strcmp(ptr,"[Percussion Patches]\n") == 0)
        {
        break;
        }
    }

if (ptr != NULL)
    {
    while(TRUE)
        {
        ptr = fgets(patch_line,MAXPATH,fp);
        if (*ptr == '\n' ||  ptr == NULL || *ptr == '[')
            break;
        if (*ptr == '#')
            continue;
#ifdef DEBUG
         printf("%s",patch_line);
#endif
        load_patch(patch_line,TYPE_PERC,size);
        }
    }
}

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

FUNCTION DEFINITION:
ClearData -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void ClearData(unsigned long size)
{
unsigned int loop_count;
unsigned int i;
char *clear_buff;

#define CLEAR_SIZE    (16U*1024U)

clear_buff = malloc(CLEAR_SIZE);
if (clear_buff == NULL)
    {
    printf("Can't zap buffer (%d)\n",CLEAR_SIZE);
    return;
    }

loop_count = size/CLEAR_SIZE;

for (i=0;i<CLEAR_SIZE;i++)
//    clear_buff[i] = 0x80;
    clear_buff[i] = 0x00;

for (i=0;i<loop_count;i++)
    {
    CopyData(clear_buff,0x00,(long)i*(long)CLEAR_SIZE, CLEAR_SIZE);
//  printf("write %lx size = %x\n",(long)i*(long)CLEAR_SIZE,CLEAR_SIZE);
    }
            
free(clear_buff);
}

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

FUNCTION DEFINITION:
Write_Library -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void Write_Library(int size)
{
unsigned char lib_name[MAXPATH];
int fd;
unsigned int length;
unsigned int info_size;
unsigned int loop_count;
unsigned char adlib[32];
int i;
char *xfer_buff;

sprintf(lib_name,"%s%d.iwl",OUT_FILE,size);
unlink(lib_name);
fd = open( lib_name, O_CREAT|O_BINARY|O_RDWR,S_IREAD|S_IWRITE );
if(fd == -1 )
    {
    printf("Error creating Lib file (%s)\n",lib_name);
    return;
    }

// First, write out the header information to the file ....
if (write(fd,&lib_header,sizeof(SBOS_LIB_HEADER)) != sizeof(SBOS_LIB_HEADER))
        printf(" Error writing lib header (%s)\n",lib_name);

length = sizeof(WAVE_INFO)*current_wave;
if (write(fd,wave_info,length) != length)
        printf(" Error writing wave parms (%s)\n",lib_name);
        
length = sizeof(WAVE_DATA)*current_wave;
if (write(fd,wave_data,length) != length)
        printf(" Error writing wave data (%s)\n",lib_name);

length = sizeof(SYN_ENVELOPE)*current_wave;
if (write(fd,mpu_info,length) != length)
        printf(" Error writing mpu info (%s)\n",lib_name);

// Put this data in the image file ....
CopyData(&map1.perc_map[0],0x00,DRAM_PERC_MAP,128*2);

// OK. Put the waves in DRAM image ....
info_size = length = sizeof(WAVE_INFO)*current_wave;
CopyData(&wave_info[0],0x00,DRAM_WAVE_INFO,length);

// OK. Load the envelopes into DRAM image also
length = sizeof(SYN_ENVELOPE)*current_wave;
info_size = ((info_size + 31L) & -32L);
CopyData(&mpu_info[0],0x00,DRAM_WAVE_INFO+info_size,length);

// OK. Load the Adlib DC offsets into DRAM image
for (i=0;i<32;i++)
    adlib[i] = 0x55;

CopyData(&adlib[0],0x00,DRAM_STOPPED_VOICE,32);

// OK. Now append the data from the image file ...
lseek(lib_fd,0L,0);        // seek back to the beginning .....
lseek(fd,0L,2);            // seek lib file to the end

#define XFER_SIZE    (16U*1024U)

xfer_buff = malloc(XFER_SIZE);
if (xfer_buff == NULL)
    {
    printf("Can't allocate xfer buffer (%d)\n",XFER_SIZE);
    return;
    }

loop_count = ((unsigned long)size*1024L)/XFER_SIZE;

for (i=0;i<loop_count;i++)
    {
    if (read(lib_fd,xfer_buff,XFER_SIZE) != XFER_SIZE)
        break;
    if (write(fd,xfer_buff,XFER_SIZE) != XFER_SIZE)
        {
        printf("Unable to append image data to lib file\n");
        break;
        }
    }
            
free(xfer_buff);

// We're DONE !!!!
close(fd);
}
/****************************************************************************

FUNCTION DEFINITION:
Build_Sustain -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void Build_Sustain(void)
{
FILE *cfg_fp;
char patch_line[MAXPATH];
char *ptr;
int num_elements=0;

cfg_fp = fopen(CFG_FILE,"r");
rewind(cfg_fp);

// Lets do Melodics first .... 
while(TRUE)
    {
    ptr = fgets(patch_line,MAXPATH,cfg_fp);
    if (ptr == NULL)
        break;
    if (strcmp(ptr,"[Melodic Patches]\n") == 0)
        {
        break;
        }
    }

if (ptr != NULL)
    {
    while(TRUE)
        {
        ptr = fgets(patch_line,MAXPATH,cfg_fp);
        if (*ptr == '\n' ||  ptr == NULL || *ptr == '[')
            break;
        if (*ptr == '#')
            continue;
        get_sustain_bit(TYPE_MELODIC,patch_line,1024,
                        &(lib_header.sustain[num_elements]));
        num_elements++;
        }
    }

rewind(cfg_fp);
// Lets do Percs next .... 
while(TRUE)
    {
    ptr = fgets(patch_line,MAXPATH,cfg_fp);
    if (ptr == NULL)
        break;
    if (strcmp(ptr,"[Percussion Patches]\n") == 0)
        {
        break;
        }
    }

if (ptr != NULL)
    {
    while(TRUE)
        {
        ptr = fgets(patch_line,MAXPATH,cfg_fp);
        if (*ptr == '\n' ||  ptr == NULL || *ptr == '[')
            break;
        if (*ptr == '#')
            continue;
        get_sustain_bit(TYPE_PERC,patch_line,1024,
                    &(lib_header.sustain[num_elements]));
        num_elements++;
        }
    }

fclose(cfg_fp);
}

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

FUNCTION DEFINITION:
Build_Library -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void Build_Library(int size)
{
int dram_len;
FILE *cfg_fp;
unsigned long start;
int i;
char filename[256];

end_dram = ((size*1024L)-128L);
num_samples = 0;

lib_header.major = VERSION_HIGH;
lib_header.minor1 = VERSION_LOW1;
lib_header.minor2 = VERSION_LOW2;
lib_header.patch_info.start_basic = 0;
lib_header.patch_info.start_melodics = 0;
lib_header.patch_info.start_percs = 0;
lib_header.patch_info.start_effects = 0;

current_wave = lib_header.num_waves = 0;
lib_header.num_basic = 0;
lib_header.num_melodics = 0;
lib_header.num_percs = 0;
lib_header.num_effects = 0;

// OPEN UP DATA FILE HERE ....
unlink("image.dat");
lib_fd = open( "image.dat", O_CREAT|O_BINARY|O_RDWR,S_IREAD|S_IWRITE );
if(lib_fd == -1 )
    {
    printf("Error creating Lib file (image.dat)\n");
    return;
    }

ClearData((unsigned long)(size*1024L));    // Write 0x80's to entire data file ....

cfg_fp = fopen(CFG_FILE,"r");
if (cfg_fp == NULL)
    {
    printf("\nCan't find %s file\n",CFG_FILE);
    getch();
    close(lib_fd);
    return;
    }

display_header(size);

Build_Sustain();

Build_Basic(cfg_fp,size);

Build_Melodics(cfg_fp,size);

Build_Percs(cfg_fp,size);

lib_header.num_waves = current_wave;

for (i=0;i<lib_header.num_basic;i++)
    lib_header.lib_map.basic_map[i] = map2.basic_map[map1.basic_map[i]];

for (i=0;i<lib_header.num_melodics;i++)
    lib_header.lib_map.melodic_map[i] = map2.melodic_map[map1.melodic_map[i]];

for (i=0;i<lib_header.num_percs;i++)
    lib_header.lib_map.perc_map[i] = map2.perc_map[map1.perc_map[i]];

for (i=0;i<lib_header.num_effects;i++)
    lib_header.lib_map.effect_map[i] = map2.effect_map[map1.effect_map[i]];

fclose(cfg_fp);

lib_header.dram_info.dram_begin = 0L;
lib_header.dram_info.dram_stopped_voice = DRAM_STOPPED_VOICE;
lib_header.dram_info.dram_temp_buff = DRAM_TEMP_BUFF;
lib_header.dram_info.dram_perc_map = DRAM_PERC_MAP;
lib_header.dram_info.dram_wave_info = DRAM_WAVE_INFO;
start = DRAM_WAVE_INFO+current_wave*sizeof(WAVE_INFO)+31L;
start &= -32L; // round up to 32 byte boundary
lib_header.dram_info.dram_mpu_info = start;

Write_Library(size);
close(lib_fd);

// Now remove the image file ...
unlink("image.dat");

return;
}

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

FUNCTION DEFINITION:
GetFFFs -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
int GetFFFs(void)
{
int rc;
unsigned char def_vendor[80];
unsigned char vendor_buf[80];
unsigned char fff_line[80];
unsigned char tpath[80];
unsigned char *ptr;
unsigned char *patch_ptr;
int i;

ini_file = "iwsbos.ini";

// OK. I have the path and name of the iwsbos.ini file ...
//[vendors]
//eye=gm.fff,gmdrums.fff
//default=eye

//[vendor eye]
//gm.fff=c:\iw\patches
//gmdrums.fff=c:\iw\patches

// First init all fff_files to NULL
for (i=0;i<10;i++)
    {
    fff_info[i].fff_data = NULL;
    }

rc = iwu_get_profile_string("vendors","default","",def_vendor,80,ini_file);
if (rc == 0)
    {
    printf("No default patch set defined\n");
    return(0);
    }

// OK. Now get this vendor's FFF files
rc = iwu_get_profile_string("vendors",def_vendor,"",fff_line,80,ini_file);
if (rc == 0)
    {
    printf("No FFF file definitions found\n");
    return(0);
    }

// OK. now open this vendor's section and get path to GM melodics set
sprintf(vendor_buf,"vendor %s",def_vendor);

ptr = iwu_strtok(fff_line,",");        // point to FFF file

for (i=0;i<10;i++)
    {
    if (ptr == NULL)
        break;
    
    rc = iwu_get_profile_string(vendor_buf,ptr,"",tpath,80,ini_file);
    if (rc == 0)
        {
        return(0);
        }
    if (strcmp(tpath,"%PATCHES%") == 0)
        {
        patch_ptr = getenv("PATCHES");
        if (patch_ptr == NULL)
            {
            printf("No PATCHES environment variable found.\n");
            getch();
            exit(-1);
            }
        sprintf(fff_info[i].fff_file,"%s\\%s",patch_ptr,ptr);
        strcpy(fff_info[i].fff_path,patch_ptr);
        }
    else
        {
        sprintf(fff_info[i].fff_file,"%s\\%s",tpath,ptr);
        strcpy(fff_info[i].fff_path,tpath);
        }
    ptr = iwu_strtok(NULL,",");        // point to FFF file
    }

num_fffs = i;

return(1);
}


void
PeekString(void)
{
// Keep linker happy... This will never get called by builder code ...
}

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

FUNCTION DEFINITION:
main -

DESCRIPTION:

EXPECTS:

MODIFIES:

SEE ALSO:

RETURNS:

*/
void main(int argc,char *argv[])
{
int dram_len;

if (argc == 2)
    {
    if (strcmp(argv[1],"/L") == 0)
        listing = TRUE;
    }

ctrlbrk( control_break );

if (access(CFG_FILE,0) != 0)
    {
    printf("Can't find %s lib config file.\n",CFG_FILE);
    exit(-1);
    }

if (!GetFFFs())
    exit(-1);
LoadFFFs();

wave_info = (WAVE_INFO *)malloc(1000*sizeof(WAVE_INFO));
wave_data = (WAVE_DATA *)malloc(1000*sizeof(WAVE_DATA));

mpu_info = (SYN_ENVELOPE *)malloc(1000*sizeof(SYN_ENVELOPE));

if (wave_info == NULL || wave_data == NULL)
    {
    printf("Unable to allocate the wave data structures\n");
    exit(-5);
    }

Build_Library(512);
Build_Library(1024);

UnloadFFFs();

exit(0);
}
