/* simple decoder to read WAV file header info */

#include <stdio.h>
#include "kernel.h"
#include <swis.h>

_kernel_swi_regs rin,rout;

FILE* infile;
FILE* outfile;
FILE* outfile2;

char infilename[256];
char inleafname[64];
char outfilename[256];

char ChunkID[5],Format[5],Subchunk1ID[5],Subchunk2ID[5];
char string1[256];

char c1,c2,c3;

int ChunkSize,Subchunk1Size,AudioFormat;
int NumChannels,SampleRate,ByteRate,BlockAlign;
int BitsPerSample,Subchunk2Size,BytesPerSample;
int blocksize;

int i,ok,lint,rint,icut,icut2,icut24,icut224;

double duration,dt,dt_ms,t_ms,duration_ms,scale,scale24;

double tstart,tdone,tnow;

int check_inputfile(void);

void get4(char*);
int get4int(void);
int get2int(void);

void read_settings_file(void);

int read_payload(void);

int main(void)
{
  
  printf("\nWAV reader V1.00 JCGL April 2010\n\n");
  
  icut=32768; icut2=icut*2;
  scale=1.0/(double)icut;
  
  icut24=icut*256; icut224=icut2*256;
  scale24=1.0/(double)icut24;
  
  read_settings_file();
  printf("Input file Name => ");
  scanf("%s",inleafname);
  sprintf(infilename,"%s.%s\0",string1,inleafname);
  printf("Full name = %s\n\n",infilename);
  ok=check_inputfile();
  
  if(ok>0)
  {
    printf("Reading header\n");
    infile=fopen(infilename,"rd");
    get4(ChunkID);
    printf("ChunkID = %s\n",ChunkID);
    ChunkSize=get4int();
    printf("Chunk Size = %d\n",ChunkSize);
    
    get4(Format);
    printf("Format = %s\n",Format);
    get4(Subchunk1ID);
    printf("Subchunk1ID = %s\n",Subchunk1ID);
    Subchunk1Size=get4int();
    
    AudioFormat=get2int();
    
    if((Subchunk1Size==16)&&(AudioFormat==1))
    {
      printf("16 bits per sample LPCM format OK\n");
    }
    else
    {
      printf("Format unknown!\n");
    }
    
    NumChannels=get2int();
    printf("Number of Channels = %d\n",NumChannels);
    SampleRate=get4int();
    printf("Sample Rate = %d\n",SampleRate);
    ByteRate=get4int();
    printf("Byte Rate = %d\n",ByteRate);
    
    BlockAlign=get2int();
    printf("Block Align = %d\n",BlockAlign);
    BitsPerSample=get2int();
    printf("Bits per sample = %d\n",BitsPerSample);
    BytesPerSample=BitsPerSample/8;
    printf("Bytes per sample = %d\n",BytesPerSample);
    
    get4(Subchunk2ID);
    printf("Subchunk2ID = %s\n",Subchunk2ID);
    Subchunk2Size=get4int();
    printf("Subchunk2Size = %d [Number of Data payload bytes]\n",Subchunk2Size);
    printf("(Header size = %d)\n",ok-Subchunk2Size);
    
    i=read_payload();
    
    fclose(infile);
    
    blocksize=ByteRate;
    
    printf("Block Size for 1 sec %d Bytes\n\n",blocksize);
    
    
    blocksize=blocksize/10;
    
    printf("Block Size for 0.1 sec %d Bytes\n\n",blocksize);
    
  }
  
}


void read_settings_file(void)
{
  /* Reads the settings file inside the application to allow
     some flexibility of the program settings */
  
  FILE* setfile;
  setfile=fopen("<Obey$Dir>.Settings\0","rt");
  
  fscanf(setfile,"%s",string1);
  printf("Source file dir = %s\n\n",string1);
}



int read_payload(void)
{
  double left,right;
  
  int offset_samples,offset_bytes;
  
  
  if(NumChannels==1) printf("\n\nMono Source\n\n");
  if(NumChannels==2) printf("\n\nStereo\n\n");
  dt=1.0/(double)SampleRate;
  duration=(double)Subchunk2Size;
  duration=duration*dt/(double)NumChannels;
  duration=duration/(double)BytesPerSample;
  duration_ms=duration*1000.0;
  printf("Duration of data = %6.3lf sec\n",duration);
  dt_ms=dt*1000.0;
  printf("Sample interval = %6.4lf ms\n\n",dt_ms);
  
  printf("Enter start time of portion to read [sec] => ");
  
  scanf("%lf",&tstart);
  
  if(tstart<0.0) tstart=0.0;
  
  if(tstart>(duration-0.2)) tstart=duration-0.2;
  
  offset_samples=(int)(tstart*(double)SampleRate);
  
  offset_bytes=offset_samples*BytesPerSample*NumChannels;
  
  printf("Start at sample (pair) %d  byte %d\n",offset_samples,offset_bytes);
  
  
  fseek(infile,offset_bytes,1);
  
  sprintf(outfilename,"ram:waveout_%s\0",inleafname);
  
  printf("Output waves written to %s\n",outfilename);
  
  outfile=fopen(outfilename,"wt");
  
  sprintf(outfilename,"ram:values_%s\0",inleafname);
  
  printf("Output values written to %s\n",outfilename);
  
  outfile2=fopen(outfilename,"wt");
  
  i=0; t_ms=0.0;
  
  printf("Writing output.\n");
  
  do
  {
    if(BytesPerSample==2)
    {
      fscanf(infile,"%c%c",&c1,&c2);
      lint=(int)c1 + 256*(int)c2;
      if (lint>=icut) lint-=icut2;
   }
   
   if(BytesPerSample==3)
   {
     fscanf(infile,"%c%c%c",&c1,&c2,&c3);
     lint=(int)c1 + 256*(int)c2 + 65536*(int)c3;
     if (lint>=icut24) lint-=icut224;
     
   }
    
    
    if(NumChannels==1)
    {
      rint=lint;
    }
    else
    {
      
      if(BytesPerSample==2)
      {
        fscanf(infile,"%c%c",&c1,&c2);
        rint=(int)c1 + 256*(int)c2;
        if (rint>=icut) rint-=icut2;
      }
   
     if(BytesPerSample==3)
     {
       fscanf(infile,"%c%c%c",&c1,&c2,&c3);
       rint=(int)c1 + 256*(int)c2 + 65536*(int)c3;
       if (rint>=icut24) rint-=icut224;
      }
      
    }
    
    if(BytesPerSample==2)
    {
      left=scale*(double)lint;
      right=scale*(double)rint;
    }
    
    if(BytesPerSample==3)
    {
      left=scale24*(double)lint;
      right=scale24*(double)rint;
    }
    
    
    fprintf(outfile,"%10.5lf, %8.5lf, %8.5lf\n",t_ms,left,right);
    
    fprintf(outfile2,"%d, %d, %d\n",i,lint,rint);
    
    i++;
    
    t_ms+=dt_ms;
    
  } while (t_ms<100.0);
  
  fclose(outfile);
  fclose(outfile2);
  printf("done!\n");
  
  return i;
}


int get2int(void)
{
  int result;
  char cip1,cip2;
  
  fscanf(infile,"%c",&cip1);
  fscanf(infile,"%c",&cip2);

  result=(int)cip2;
  result=(int)cip1+256*result;

  return result;
} 

int get4int(void)
{
  int result;
  char cip1,cip2,cip3,cip4;
  
  fscanf(infile,"%c",&cip1);
  fscanf(infile,"%c",&cip2);
  fscanf(infile,"%c",&cip3);
  fscanf(infile,"%c",&cip4);
    
  result=(int)cip4;
  result=(int)cip3+256*result;
  result=(int)cip2+256*result;
  result=(int)cip1+256*result;
  
  return result;
} 
void get4(char* outstring)
{
  int isp;
  char csp;
  isp=0;
  do
  {
    fscanf(infile,"%c",&csp);
    outstring[isp]=csp;
    isp++;
  } while (isp<4);
  outstring[4]=(char)0;

}


int check_inputfile(void)
{
  
  /* This procedure checks that the named input file exists
     and if it does, reports its duration */
  
  int ilb;
  
  
  rin.r[0]=5;
  rin.r[1]=(int)infilename;
  _kernel_swi(OS_File,&rin,&rout);
  if(rout.r[0]==1)
  {
    ilb=rout.r[4];
    
    
    
    printf("Input file %d bytes long\n\n",ilb);
  }
  else
  {
    ilb=0;
    
    printf("Input file does not exist!\n");
  }
  return ilb;
}

