#include <stdio.h>
#include <math.h>

/************************************************************************/
/* matrixread - allows MFCC data area to be read like a matrix		*/
/* Passed:	x: x co-ordinate required (frame)			*/
/*		y: y co-ordinate required (coefficient)			*/
/*		coeffs: number of coefficients per frame		*/
/*		*data: pointer to data area				*/
/* Passes: 	data value at desired co-ordinate			*/
/************************************************************************/
float matrixread(int x,int y,int coeffs,float *data)
	{
	return(data[(x*coeffs)+y]);
	}


/************************************************************************/
/*ReadMFCC - reads MFCC file into memory			        */
/*Passed: 	*inputfile: pointer to opened MFCC file			*/
/*		*coeffs: number of co-efficients in MFCC		*/
/*		*frames: number of frames in MFCC			*/
/*Returns: pointer to (float)allocated memory, or 0 on failure		*/
/************************************************************************/

float *ReadMFCC(FILE *inputfile,int *frames,int *coeffs)
	{
	typedef struct 
		{              /* HTK File Header */
		long nSamples;
		long sampPeriod;
		short sampSize;
		short sampKind;
		} HTKhdr;
	HTKhdr hdr;
	float *data;
	int n;

	fread(&hdr, 1, sizeof(HTKhdr), inputfile); 	
		if(hdr.sampKind!= 70)
			{
			fprintf(stderr,"Error: File format not MFCC_E\n");
			return(0);
			}
	data = (float *)malloc(hdr.sampSize*hdr.nSamples);
	n = fread(data,4,(hdr.sampSize/4)*hdr.nSamples,inputfile);
	if(n<(hdr.sampSize/4)*hdr.nSamples)
		{
		fprintf(stderr,"Error: could not read all MFCC values\n");
		free(data);
		return(0);
		}
	*coeffs = hdr.sampSize/4;
	*frames = hdr.nSamples;
	return(data);
	}


float d(int x,int y, int coeffs, float *templatedata, float *patterndata)
{
  float coeffcost,localcost;
  int a;

  coeffcost=0.0; localcost=0.0;

  for(a=0;a<coeffs;a++) 
    {
    coeffcost=templatedata[(y*coeffs)+a] - patterndata[(x*coeffs)+a];
    localcost=localcost+(coeffcost*coeffcost);
    }
  return(sqrt(localcost));
}



float min3(float var1, float var2, float var3)
{
  if (var1<var2) 
    {
    if (var1<var3) 
      return(var1);
    else 
      return(var3); 
    }
  else 
    {
    if (var2<var3) 
      return(var2); 
    else 
      return(var3); 
    }
}

float min2(float var1, float var2)
{
  if (var1<var2)
    return var1;
  else
   return var2;
}

int isSpecial(int col, int row)
{
  int specialStart;
  specialStart = (2*col)-1;
  return ((row>=specialStart) && (row<=(specialStart+1)));
}

/* Takes the pattern file as an argument on the command line   */
/* Cycles through all template files with format:              */
/* speakernum_word_setnum.mfcc                                 */
/* speakernum is {1,2,3,5}                                     */
/* word is {yes, no, across, down, one, two, ..., nine}        */
/* setnum is {1,2,3,4,5,6,7,8}                                 */

void main(int argc , char **argv)
	{
        /* Begin variable declarations */

        FILE *templateinputfile;
        FILE *patterninputfile;
        int templateframes,patternframes,coeffs;

        float *curCol;
       	float *predCol;

        float *tdata;
        float *pdata;
        float lowestGlobal;

        int p,i,j,maxj;
        int wordindex,speaker,set,wordnum,pwordnum,pset,pspeaker;

        char ext[6];
        char dir[35];
        char speakernum[4][2];
        char word[13][7];
        char setnum[8][2];
        char filename[55];
        char pfilename[55];

        /* Begin filename construction array definitions */
        strcpy(ext,".mfcc");
        strcpy(dir,"/home/u5snw/com326/templates/");        
        strcpy(speakernum[0],"1");
        strcpy(speakernum[1],"2");
        strcpy(speakernum[2],"3");
        strcpy(speakernum[3],"5");        
        strcpy(word[0],"yes");
        strcpy(word[1],"no");
        strcpy(word[2],"across");
        strcpy(word[3],"down");
        strcpy(word[4],"one");
        strcpy(word[5],"two");
        strcpy(word[6],"three");
        strcpy(word[7],"four");
        strcpy(word[8],"five");
        strcpy(word[9],"six");
        strcpy(word[10],"seven");
        strcpy(word[11],"eight");
        strcpy(word[12],"nine");        
        strcpy(setnum[0],"1");
        strcpy(setnum[1],"2");
        strcpy(setnum[2],"3");
        strcpy(setnum[3],"4");
        strcpy(setnum[4],"5"); 
        strcpy(setnum[5],"6");
        strcpy(setnum[6],"7");
        strcpy(setnum[7],"8");
        
        wordindex=13;





        /* Read in each pattern data. Abort if the file connot be opened. */
        printf("\nAsymmetric dynamic programming\n");        
        for(pwordnum=0;pwordnum<13;pwordnum++) 
          {
          printf("\n%s: ",word[pwordnum]);
          for(pspeaker=0;pspeaker<4;pspeaker++)
            {
            for(pset=0;pset<8;pset++)
              {
              strcpy(pfilename, dir);
              strcat(pfilename, speakernum[pspeaker]);
              strcat(pfilename, "_");
              strcat(pfilename, word[pwordnum]);
              strcat(pfilename, "_");
              strcat(pfilename, setnum[pset]);
              strcat(pfilename, ext);

              /* Only compare if the template could be opened. */
	      patterninputfile = fopen(pfilename,"r");
      	      if (patterninputfile!=NULL)
                {
                pdata = ReadMFCC(patterninputfile,&patternframes,&coeffs);



                /* Compare the pattern with each template file. */
                wordindex=13;
                for(speaker=0;speaker<4;speaker++)
                  {
                  if (pspeaker!=speaker)
{
                  for(wordnum=0;wordnum<13;wordnum++) 
                    {
                    for(set=0;set<8;set++)
                      {
                      strcpy(filename, dir);
                      strcat(filename, speakernum[speaker]);
                      strcat(filename, "_");
                      strcat(filename, word[wordnum]);
                      strcat(filename, "_");
                      strcat(filename, setnum[set]);
                      strcat(filename, ext);
  
                      if (strcmp(pfilename,filename)!=0) /* don't compare if files are same */
                        {
                        /* Only compare if the template could be opened. */
       	                templateinputfile = fopen(filename,"r");
                        if (templateinputfile!=NULL)
                          { 
                          tdata = ReadMFCC(templateinputfile,&templateframes,&coeffs);

                          predCol = (float *)malloc(sizeof(float)*templateframes);
                          curCol  = (float *)malloc(sizeof(float)*templateframes);

                          predCol[0]=d(0,0,coeffs,tdata,pdata);

                          for(i=1;i<patternframes;i++) 
                            {
                            curCol[0]=d(i,0,coeffs,tdata,pdata)+predCol[0];

                            for(j=1;((j<((2*i)+1))&&(j<templateframes));j++)
                              {
                              maxj=j;
                              if (isSpecial(i,j))
                                {
                                if (j==1)
                                  curCol[j]=predCol[j-1]+d(i,j,coeffs,tdata,pdata);
                                else
                                  {
                                  if (j%2==1)
                                    curCol[j]=min2(predCol[j-1],predCol[j-2])+d(i,j,coeffs,tdata,pdata);
                                  else
                                    curCol[j]=predCol[j-2]+d(i,j,coeffs,tdata,pdata);
                                  }
                                }
                              else
                                {
                                if (j==1)
                                  curCol[j]=min2(predCol[j],predCol[j-1])+d(i,j,coeffs,tdata,pdata);
                                else
                                  curCol[j]=(min3(predCol[j],predCol[j-1],predCol[j-2])+d(i,j,coeffs,tdata,pdata));
                                }
                              }
                            free(predCol);  
                            predCol=curCol;
                            curCol = (float *)malloc(sizeof(float)*templateframes); 
                            }
                          if (wordindex==13) /* ie first time round loop(s) */
                            {
                            lowestGlobal=predCol[maxj];
                            wordindex=wordnum; 
                            }
                          else 
                            {
                            if (predCol[maxj] < lowestGlobal)
                              {
                              lowestGlobal=predCol[maxj];
                              wordindex=wordnum;
                              }
                            }
                          free(curCol);
                          free(predCol);
                          free(tdata);  
                          fclose(templateinputfile);
                          } 
                        }
                      }
                   }}    
                  }
                free(pdata);
                fclose(patterninputfile);
                if (wordindex!=13)
                  printf(" %s ",word[wordindex]);
                else
                  printf("Error locating template files in %s\n",dir);
                }
              }
            }
          }
        }

