/**************************************/
/*                                    */
/*     Nagravision sound decoder      */
/*                                    */
/*          by  Galtor 1999           */
/*                                    */
/**************************************/

#include <stdlib.h>                         
#include <stdio.h>

#include <fcntl.h>
#include <math.h>
#include <string.h>

#include <curses.h>

#ifdef ALSA

#include <sys/asoundlib.h>
#include <linux/asound.h>
#include <linux/asoundid.h>

#else

#include <linux/soundcard.h>

#endif

#include "nagraudio.h"
#include "wavhead.h"

/*******************************************/
/************ FILTER DEFINITION ************/
/*******************************************/

/* The user level n are internal n*2-1 level !! */

 
 int in_coef[MAX_ORDER+1][MAX_ORDER]={
   {},{},{},{0,3},{},{0,5,10},{},{0,7,21,35}};

/************ POST MODULATION FILTER DEFINITION **************/

int post_out_coef[MAX_ORDER+1][MAX_ORDER+1]={
  {}, 
  
  {0,0.0731489272*(1<<PRECISSION)},                                  //Level 1 
  
  {},
  
  {0,0.2678654389*(1<<PRECISSION),-0.3523244053*(1<<PRECISSION),     //Level 3 
     0.0247302699*(1<<PRECISSION)},

  {},
  
  {0,0.4576942144*(1<<PRECISSION),-0.7067341465*(1<<PRECISSION),     //Level 5 
     0.1603017017*(1<<PRECISSION),-0.0670410490*(1<<PRECISSION),
     0.0043118519*(1<<PRECISSION)},

  {},

  {0,0.6455546255*(1<<PRECISSION),-1.0827483976*(1<<PRECISSION),     //Level 7
     0.4131654344*(1<<PRECISSION),-0.2552919195*(1<<PRECISSION),
     0.0500299877*(1<<PRECISSION),-0.0111237227*(1<<PRECISSION),
     0.0006362623*(1<<PRECISSION)}};


int post_gains[MAX_ORDER+1]={0,
			     2.157843972*(1<<PRECISSION),0,
			     7.549101979*(1<<PRECISSION),0,
			     27.79062545*(1<<PRECISSION),0,
                             103.2443130*(1<<PRECISSION)};


/************ PRE MODULATION FILTER DEFINITION ***************/

int pre_out_coef[MAX_ORDER+1][MAX_ORDER+1]={
  {},
  
  {0,-0.1416306738*(1<<PRECISSION)},                                  //Level 1 

  {},
  
  {0,-0.5168039063*(1<<PRECISSION),-0.4041813836*(1<<PRECISSION),     //Level 3
     -0.0497187889*(1<<PRECISSION)},
  
  {},

  {0,-0.8823852003*(1<<PRECISSION),-0.9062925254*(1<<PRECISSION),     //Level 5
     -0.3366224025*(1<<PRECISSION),-0.0995725400*(1<<PRECISSION),
     -0.0096268552*(1<<PRECISSION)},

  {},

  {0,-1.2442434093*(1<<PRECISSION),-1.5253656891*(1<<PRECISSION),     //Level 7
     -0.9065143396*(1<<PRECISSION),-0.4407574247*(1<<PRECISSION),
     -0.1209858632*(1<<PRECISSION),-0.0220286561*(1<<PRECISSION),
     -0.0016585133*(1<<PRECISSION)}};
 
int pre_gains[MAX_ORDER+1]={0,
			    1.751880048*(1<<PRECISSION),0,
			    4.059462852*(1<<PRECISSION),0,
			    9.893338913*(1<<PRECISSION),0,
                            24.32741402*(1<<PRECISSION)};

/*********************************************/
/********** END OF FILTER DEFINITION *********/
/*********************************************/

/************** GLOBAL VARIABLES *************/

int bits=16;
int DEC_FREQ=44100;
int OUT_GAIN=1;           /* 0= no gain, 1= x2, 2= x4 ,3= x8 */

#ifdef ALSA
  snd_pcm_t *handle;            /* Alsa card handle */
#else
  char device[20]="/dev/dsp";
#endif

int decode=1;
int auto_decode=0;
int pre_filter_level=0;
int post_filter_level=0;

WINDOW *mainwin;           /* ncurses main window */
int gui=1;

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

void write_wav_header(int sfdes, int data_length)
{
  wavhead header;
  
  char *riff = "RIFF";
  char *wave = "WAVE";
  char *fmt  = "fmt ";
  char *data = "data";
  
  memcpy(&(header.main_chunk), riff, 4);
  header.length = sizeof(wavhead) - 8 + data_length;
  memcpy(&(header.chunk_type), wave, 4);
  
  memcpy(&(header.sub_chunk), fmt, 4);
  header.sc_len = 16;
  header.format = 1;
#ifdef ALSA
  header.modus = MONO_STEREO;
#else
  header.modus = MONO_STEREO+1;
#endif
  header.sample_fq = DEC_FREQ;
  header.byte_p_sec = ((bits > 8)? 2:1)*header.modus*DEC_FREQ;
  header.byte_p_spl = (bits > 8)? 2:1;
  header.bit_p_spl = bits;
  
  memcpy(&(header.data_chunk), data, 4);
  header.data_length = data_length;
  write(sfdes, &header, sizeof(header));  
}


int open_sound_file (int type)
{ 
  int  themask,sfdes;
  char filename[100]=""; 
  char num[4]=""; 
  char aux[100]="";
  char ext[5];
  int  i;
  
  if (type)
    strcpy(ext,".wav");
  else
    strcpy(ext,".raw");
  
  strcpy(filename,DEFAULT_FILE_PATH); 
  strcat(filename,"/nagraudio");
  
  for (i=0;i<1000;i++){
    sprintf(num,"%.3d",i);
    strcpy(aux,filename);
    strcat(aux,num);
    strcat(aux,ext);
    if (open(aux,O_RDONLY)==-1) break;
  } 
  
  themask=umask(0);
  umask(themask);
  sfdes=open(aux, O_CREAT | O_TRUNC | O_WRONLY , (~themask) & 0666 ); 
  
  if (sfdes==-1) 
    mvprintw(18,2,"Error opening sound file");
  else
    {
      mvprintw(18,2,"Writing to %s ... ",aux);
      if (type)
	write_wav_header(sfdes,0);
    }
  
  return sfdes;
  
}

void close_sound_file(int sfdes, int type, int writed_buf)
{
  if (type=2)
    {
      lseek(sfdes,0,SEEK_SET);
      write_wav_header(sfdes,writed_buf*SIZE_BUFFER*sizeof(short int));
    };
  close(sfdes);
  mvprintw(18,2,"                                                    ");
}


void init_curses()
{
  mainwin=initscr();
  cbreak();
  noecho();
  curs_set(0);
  nodelay(mainwin,TRUE);
  refresh();
}

void error_exit(char *message,int number)
{
  if ((number==2) && gui)
    {
      erase();
      refresh();
      endwin();  
    }
  fprintf(stderr,"\n");
  fprintf(stderr,message);
  fprintf(stderr,"\n");
  exit(number);
}

void do_audio_decode_44() {
  
  short int *pre_buffer_in,*aux1;
  short int *pre_buffer_out,*aux2;
  short int *post_buffer_in,*aux3;
  short int *post_buffer_out,*aux4;
  short int *modulation_in,*modulation_out,*aux5;
  short int *dec_table,*out;
  int fd,i;
  int j,temp_out;                         /* Filters variables */ 
  
  int k,pos,changes;                      /* Auto decode */
  int inertia=0;                          /* variables */
  
  int sfdes,writed_buf,writing=0;         /* Sound file descriptor & writing flag*/
  int key=0;				  /* Key pressed */
  
  pre_buffer_in=malloc((SIZE_BUFFER+MAX_ORDER)*sizeof(short int));
  memset(pre_buffer_in,0,(SIZE_BUFFER+MAX_ORDER)*sizeof(short int));
  pre_buffer_in+=MAX_ORDER;
  aux1=pre_buffer_in;

  pre_buffer_out=malloc((SIZE_BUFFER+MAX_ORDER)*sizeof(short int));
  memset(pre_buffer_out,0,(SIZE_BUFFER+MAX_ORDER)*sizeof(short int));
  pre_buffer_out+=MAX_ORDER;
  aux2=pre_buffer_out;

  post_buffer_in=malloc((SIZE_BUFFER+MAX_ORDER)*sizeof(short int));
  memset(post_buffer_in,0,(SIZE_BUFFER+MAX_ORDER)*sizeof(short int));
  post_buffer_in+=MAX_ORDER;
  aux3=post_buffer_in;
  
  post_buffer_out=malloc((SIZE_BUFFER+MAX_ORDER)*sizeof(short int));
  memset(post_buffer_out,0,(SIZE_BUFFER+MAX_ORDER)*sizeof(short int));
  post_buffer_out+=MAX_ORDER;
  aux4=post_buffer_out;
  
  dec_table=malloc(SIZE_BUFFER*sizeof(short int));
  aux5=dec_table;
  
  for (i=0;i<SIZE_BUFFER;i++)
    *dec_table++=(short int)((cos(M_PI*(float)i*(2.*(float)NAGRA_FREQ/(float)DEC_FREQ))*(1<<PRECISSION))-1);
  
#ifdef ALSA
  prepare_card_alsa();
#else
  fd=prepare_card_oss(16);
#endif
  

  /**** MAIN LOOP ****/
  
  while (key!='q') {
    if (gui) {
      key=getch();
      
      /**** Key pressed options ***/    
      
      if (key) {
	if (key=='r') 
	  if (writing) 
	    {
	      close_sound_file(sfdes,writing,writed_buf);
	      writing=0;
	    }
	  else 
	    {
	      sfdes=open_sound_file(0);
	      writed_buf=0;
	      if (sfdes!=-1) writing=1;
	    }
	else if (key=='w')
	  if (writing) {
	    close_sound_file(sfdes,writing,writed_buf);
	    writing=0;
	  }
	  else
	    {
	      sfdes=open_sound_file(1);
	      writed_buf=0;
	      if (sfdes!=-1)
		writing=2;
	  }
	else if (key=='a')
	  {
	    auto_decode=!auto_decode;
	    mvprintw(10,2,"a) - Auto decoding : %s",(auto_decode)? "ON ":"OFF");
	  }
	else if (key=='d')
	  {
	    decode=!decode;
	    mvprintw(8,2,"d) - Decoding      : %s",(decode)? "ON ":"OFF"); 
	  }
	else if (key=='g')
	  {
	    if (OUT_GAIN==MAX_GAIN) 
	      OUT_GAIN=0;
	    else 
	      OUT_GAIN++;
	    mvprintw(16,2,"g) - Ouput gain : x%d %s",1<<OUT_GAIN,(OUT_GAIN)? "          ":"(Disabled)");
	  }
	else if (key=='p')
	  {
	    if (pre_filter_level<MAX_ORDER) 
	      if (!pre_filter_level) pre_filter_level=1;
	      else pre_filter_level+=2;
	    else 
	      pre_filter_level=0;
	    mvprintw(12,2,"p) - Level of pre filter used  : %d %s",(pre_filter_level)? pre_filter_level/2+1:0,(pre_filter_level)? "          ":"(Disabled)");
	  }
	else if (key=='o')
	  {
	    if (post_filter_level<MAX_ORDER)
	      if (!post_filter_level) post_filter_level=1;
	      else post_filter_level+=2;
	    else
	      post_filter_level=0;
	    mvprintw(14,2,"o) - Level of post filter used : %d %s",(post_filter_level)? post_filter_level/2+1:0,(post_filter_level)? "          ":"(Disabled)");
	  }
      }
    }
    /**************************************/
    
#ifdef ALSA
    if (snd_pcm_read(handle,aux1,SIZE_BUFFER*sizeof(short int)) == -1)
      error_exit("Error reading device",2);
#else
    if (read(fd,aux1,SIZE_BUFFER*sizeof(short int)) == -1)
      error_exit("Error reading device",2);
#endif
    
    /******************* AUTODECODE RUTINE *******************/
    if (auto_decode){
      
      changes=0;
      
      pos=*(aux1)>0;
      
      for (k=1;k<20;k++)
        if (*(aux1+k)>10){
	  if (!pos){
	    changes++;
	    pos=1;
	  } 
        }
	else 
	  if (*(aux1+k)<-10)
	    if (pos){
	      changes++;
	      pos=0;
	    }
      
      
      if (changes>6){ if (inertia<5) inertia++; }
      else if (inertia>-5) inertia--;
      
      decode=!(inertia<0);
    }
    /************* END OF AUTODECODE RUTINE ****************/
    
    if (decode) {
      
      /**************** PRE MODULATION FILTER ******************/
      if (pre_filter_level)
	{
	  
	  pre_buffer_in=aux1;
	  pre_buffer_out=aux2;
	  
	  for(i=0;i<SIZE_BUFFER;i++)
	    {
	      temp_out=0;
	      
	      for (j=1;j<pre_filter_level+1;j++)
		temp_out+=pre_out_coef[pre_filter_level][j]* *(pre_buffer_out-j);
	      
              temp_out=temp_out>>PRECISSION;
	      
	      for (j=1;j<pre_filter_level/2+1;j++)
		temp_out+=in_coef[pre_filter_level][j]* (*(pre_buffer_in-j)+*(pre_buffer_in-pre_filter_level+j));
	      
	      *pre_buffer_in=(*pre_buffer_in<<PRECISSION)/pre_gains[pre_filter_level];
	      
	      temp_out+=*(pre_buffer_in-pre_filter_level)+*pre_buffer_in;
	      
	      pre_buffer_in++;
	      *pre_buffer_out++=temp_out;
	    }
	  
	  modulation_in=aux2;
	  
	  memcpy(aux2-MAX_ORDER,aux2+SIZE_BUFFER-MAX_ORDER,MAX_ORDER*sizeof(short int));
	  memcpy(aux1-MAX_ORDER,aux1+SIZE_BUFFER-MAX_ORDER,MAX_ORDER*sizeof(short int));
	  
	}
      else modulation_in=aux1;
      /************** END OF PRE MODULATION FILTER **************/
      
      /************** BEGIN OF MODULATION ******************/
      
      dec_table=aux5;
      modulation_out=aux3;
      
      for(i=0;i<SIZE_BUFFER;i++)
        *modulation_out++=(*modulation_in++**dec_table++)>>(PRECISSION-OUT_GAIN);
      
      /************** END OF MODULATION ********************/
      
      /******************* POST MODULATION FILTER *****************/
      if (post_filter_level) 
	{
	  
	  post_buffer_in=aux3;
	  post_buffer_out=aux4;
	  
	  for(i=0;i<SIZE_BUFFER;i++)
	    {
	      temp_out=0;
	      
	      for (j=1;j<post_filter_level+1;j++)
		temp_out+=post_out_coef[post_filter_level][j]* *(post_buffer_out-j);
	      
	      temp_out=temp_out>>PRECISSION;
	      
	      for (j=1;j<post_filter_level/2+1;j++)
	        temp_out+=in_coef[post_filter_level][j]* (*(post_buffer_in-j)+*(post_buffer_in-post_filter_level+j)); 
	      
              *post_buffer_in=(*post_buffer_in<<PRECISSION)/post_gains[post_filter_level];
	      
	      temp_out+=*(post_buffer_in-post_filter_level)+*post_buffer_in;
	      
              post_buffer_in++;
              *post_buffer_out++=temp_out;
	    }
	  
	  out=aux4;
	  
	  memcpy(aux3-MAX_ORDER,aux3+SIZE_BUFFER-MAX_ORDER,MAX_ORDER*sizeof(short int));
	  memcpy(aux4-MAX_ORDER,aux4+SIZE_BUFFER-MAX_ORDER,MAX_ORDER*sizeof(short int));
	  
	}
      else out=aux3;
      /*************** END OF POST MODULATION FILTER **************/
      
    }
    else 
      {
	memcpy(aux4,aux1,SIZE_BUFFER*sizeof(short int));
	out=aux4;
      }
    
#ifdef ALSA
    if (snd_pcm_write(handle,out,SIZE_BUFFER*sizeof(short int)) == -1 ) 
      error_exit("Error writing device",2);
#else
    if (write(fd,out,SIZE_BUFFER*sizeof(short int)) == -1 ) 
      error_exit("Error writing device",2);
#endif
    
    if (writing) 
      if (write(sfdes,out,SIZE_BUFFER*sizeof(short int)) == -1 )
	{ error_exit("Error writing file",2); }
      else {
	writed_buf++;
	if (gui) mvprintw(18,40,"%d Kb",(writed_buf*SIZE_BUFFER*sizeof(short int))/1024);
      }
  }
  
#ifdef ALSA
  snd_pcm_close( handle );
#endif 
  
}

#ifndef ALSA
void do_audio_decode_8()
{                                                                               
  unsigned char buffer[SIZE_BUFFER];
  unsigned char dec_table[256];  
  int fd,i;
  int key=0;
  
  for (i=0;i<255;i++)                      
    dec_table[i]=255-i;                                                      
  
  fd=prepare_card_oss(8);
  
  while (key!='q') 
    {    
      if (gui) key=getch();
      
      if (read(fd,buffer,SIZE_BUFFER) == -1)
	perror("read");
      
      for(i=0;i<SIZE_BUFFER;i+=2)
	buffer[i]=dec_table[buffer[i]];
      
      if (write(fd,buffer,SIZE_BUFFER) == -1 )
	perror("write"); 
    } 
}
#endif

#ifdef ALSA
int prepare_card_alsa ()
{
  snd_pcm_format_t format;
  snd_pcm_playback_params_t playback_params;
  snd_pcm_capture_params_t capture_params;
  int card=0;
  int device=0;
  int err;
  
  char aux_string[100];
  
  if ( (err = snd_pcm_open( &handle, card, device,
			    SND_PCM_OPEN_DUPLEX )) < 0 ) {
    sprintf(aux_string,"open failed: %s\n", snd_strerror(err));
    error_exit(aux_string,-1);
  }
  
  format.format = FORMAT;
  format.rate = DEC_FREQ;
  format.channels = MONO_STEREO;
  
  if ( (err = snd_pcm_playback_format( handle, &format )) < 0 ) {
    sprintf(aux_string, "format setup failed: %s\n",snd_strerror(err));
    error_exit(aux_string,-1);
  }
  
  if ( (err = snd_pcm_capture_format( handle, &format )) < 0 ) {
    sprintf(aux_string, "format setup failed: %s\n",snd_strerror(err));
    error_exit(aux_string,-1);
  }
  
  playback_params.fragment_size = FRAGMENT_S;
  playback_params.fragments_max = NUMBER_FRAG;
  playback_params.fragments_room = 1;
  
  if ( (err = snd_pcm_playback_params (handle, &playback_params )) < 0 ) {
    sprintf(aux_string, "playback params setup failed: %s\n",snd_strerror(err));
    error_exit(aux_string,-1);
  }
  
  capture_params.fragment_size = FRAGMENT_S;
  capture_params.fragments_min = 1;
  
  if ( (err = snd_pcm_capture_params (handle, &capture_params )) < 0 ) {
    sprintf(aux_string, "capture params setup failed: %s\n",snd_strerror(err));
    error_exit(aux_string,-1);
  }
  return 0;
} 

#else

int prepare_card_oss (int bits)                                                 
{                                                                               
  int fd,aux,caps;                                                              
  
  fd=open(device,O_RDWR);                                                       
  if (fd<0)
    error_exit("Error opening audio device",-1);
  
  if (ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0) == -1)
    error_exit("Error with full duplex setup\n",-1);
  
  if (ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == -1)
    error_exit("Sorry but your sound driver is too old\n",-1);
  
  if (!(caps & DSP_CAP_DUPLEX))
    error_exit("Sorry but your soundcard can't do full duplex\n",-1);
  
  aux=FRAGMENTS;                                                                
  if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &aux) == -1)
    error_exit("Error setting audio fragments",-1);                                             
  
  if (bits == 8) aux=FORMAT8;      
  else aux=FORMAT16;                                                            
  
  if (ioctl(fd,SNDCTL_DSP_SETFMT, &aux) == -1)
    error_exit("Error setting audio format (bits)",-1);                                                
  
  aux=MONO_STEREO;                                                              
  if (ioctl(fd,SNDCTL_DSP_STEREO, &aux) == -1)
    error_exit("Error setting audio format (stereo)",-1);
  
  aux=DEC_FREQ;                                                                 
  if (ioctl(fd,SNDCTL_DSP_SPEED, &aux) == -1)
    error_exit("Error setting audio format (frequency)",-1);                                                
  
  return fd;                                                                    
}                                                                               
#endif

void read_config()
{
  FILE *fp;
  char filename[100],line[100], tag[32], val[100], *h;
  int i,nr = 0;
  
  sprintf(filename,"%s/%s",getenv("HOME"),".nagraudiorc");
  fp = fopen(filename,"r");
  if (NULL == fp)
    fp = fopen("/etc/nagraudiorc","r");
  if (NULL == fp) {
    fprintf(stderr,"Can't open config file, using defaults\n\n");
    return;
  }
  while (NULL != fgets(line,99,fp)) {
    nr++;
    if (line[0] == '\n' || line[0] == '#' || line[0] == '%')
      continue;
    if (2 != sscanf(line," %31[^= ] = %99[^\n]",tag,val)) {
      fprintf(stderr,"%s:%d: parse error\n",filename,nr);
      continue;
    }
    for (h = val+strlen(val); h > val && *h == ' '; h--) *h='\0';
    
    if (0 == strcmp(tag,"pre_filter"))
      if (atoi(val)!=0) 
	if (atoi(val)<1 || atoi(val)>MAX_ORDER/2+1)
	  fprintf(stderr,"%s:%d: wrong valor in %s\n",filename,nr,tag);
	else
	  pre_filter_level=(atoi(val))*2-1;
      else
	pre_filter_level=0;
    
    else if (0 == strcmp(tag,"post_filter"))
      if (atoi(val)!=0) 
	if (atoi(val)<1 || atoi(val)>MAX_ORDER/2+1)
	  fprintf(stderr,"%s:%d: wrong valor in %s\n",filename,nr,tag);
	else 
	  post_filter_level=(atoi(val))*2-1;
      else
	post_filter_level=0;
    
    else if (0 == strcmp(tag,"output_gain"))
      if (atoi(val)!=0)
        if (atoi(val)<1 || atoi(val)>MAX_GAIN)
          fprintf(stderr,"%s:%d: wrong valor in %s\n",filename,nr,tag);
        else
          OUT_GAIN=atoi(val);
      else
        OUT_GAIN=0;

#ifndef ALSA 
    else if (0 == strcmp(tag,"device"))
      strcpy(device,val);
#endif
    
    else if (0 == strcmp(tag,"auto_decode"))
      if (atoi(val)==0)
	auto_decode=0;
      else if (atoi(val)==1)
	auto_decode=1;
      else 
	fprintf(stderr,"%s:%d: wrong valor in %s\n",filename,nr,tag);

    else if (0 == strcmp(tag,"gui"))
      if (atoi(val)==0)
        gui=0;
      else if (atoi(val)==1)
        gui=1;
      else
        fprintf(stderr,"%s:%d: wrong valor in %s\n",filename,nr,tag);
    
    else if (0 == strcmp(tag,"8_bits"))
      if (atoi(val)==0)
	bits=16;
      else if (atoi(val)==1)
	bits=8;
      else 
	fprintf(stderr,"%s:%d: wrong valor in %s\n",filename,nr,tag);
    
    else {
      fprintf(stderr,"%s:%d: unknown option %s\n",filename,nr,tag);
      
    }
  }
}

int main(int argc,char **argv)
{
  int c;
  int use_config=1;
  char aux_string[100];
  int x,y;  
  
  if (argc!=0) 
    for (c=1;c<argc;c++)
      if (strcmp(argv[c],"-i")==0)
	use_config=0;
  
  if (use_config) read_config();
  
  if (argc!=0) for (c=1;c<argc;c++) {
    
    if ((strcmp(argv[c],"--help")==0)||(strcmp(argv[c],"-h")==0)) {
      printf("usage: %s [-h|--help] [-v] [-i] [-d device] [-a] [-lf n] [-bf m]",argv[0]);
#ifndef ALSA       
      puts(" [-8] ");
#else
      puts("");
#endif       
      puts("");
      puts("-h,--help   show that help");
      puts("-v          show version");
      puts("-i          ignore any configuration file");
      puts("-d device   audio device [/dev/dsp]");
      puts("-a          auto decode");
      puts("-g #        level of output gain");
      puts("-post #     level of post filter");
      puts("-pre  #     level of pre filter");
      puts("-nogui      disable the ncurses gui");
#ifndef ALSA
      puts("-8          use 8 bits samples (useful for SB16 but horrible quality)");
#endif
      puts("");
      exit(0);
    }
    
#ifndef ALSA  
    if (strcmp(argv[c],"-8")==0){
      bits=8;
      DEC_FREQ=25600;
    }

    if (strcmp(argv[c],"-d")==0)
      if (c==argc-1)
        error_exit("You must especify a device",1);
      else strcpy(device,argv[c+1]);

#endif
    
    if (strcmp(argv[c],"-a")==0)
      auto_decode=1;

    if (strcmp(argv[c],"-nogui")==0)
      gui=0;
    
    if (strcmp(argv[c],"-g")==0)
      if (c==argc-1)
        error_exit("Output gain needs an argument!",1);
      else
        if (!isdigit(argv[c+1][0]))
          error_exit("Output gain needs a numerical argument!",1);
        else
          if ((atoi(argv[c+1])>MAX_GAIN)||(atoi(argv[c+1])<1)) {
            sprintf(aux_string,"The level of output gain must be between 1-%d\n",MAX_GAIN);
            error_exit(aux_string,1);
          }
          else {
            OUT_GAIN=atoi(argv[c+1]);
            c++;
          }
    
    if (strcmp(argv[c],"-post")==0)
      if (c==argc-1)
	error_exit("Post filter needs an argument!",1);
      else 
	if (!isdigit(argv[c+1][0]))
	  error_exit("Post filter needs a numerical argument!",1);
	else 
	  if ((atoi(argv[c+1])>MAX_ORDER/2+1)||(atoi(argv[c+1])<1)) {
	    sprintf(aux_string,"The level of post filter must be between 1-%d\n",MAX_ORDER/2+1);
	    error_exit(aux_string,1);
	  }
	  else
	    {
              post_filter_level=(atoi(argv[c+1]))*2-1;
              c++;
	    }
    
    
    if (strcmp(argv[c],"-pre")==0)
      if (c==argc-1)
	error_exit("Pre filter needs an argument!",1);
      else
	if (!isdigit(argv[c+1][0]))
	  error_exit("Pre needs a numerical argument!",1);
	else
	  if ((atoi(argv[c+1])>MAX_ORDER/2+1)||(atoi(argv[c+1])<1)) {
	    sprintf(aux_string,"The level of pre filter must be betwen 1-%d\n",MAX_ORDER/2+1);
	    error_exit(aux_string,1);
	  }
	  else 
	    {
	      pre_filter_level=(atoi(argv[c+1]))*2-1;
 	      c++;
	    }   
    
    
    if (strcmp(argv[c],"-v")==0) {
#ifdef ALSA
      printf("\nNagraudio %s for ALSA\n",VERSION);
#else
      printf("\nNagraudio %s\n",VERSION);
#endif
      puts("by Galtor\n\n");
      exit(0);
    }
  }
  
  
  if (bits==8) {
    pre_filter_level=0;
    post_filter_level=0;
    OUT_GAIN=0;
    auto_decode=0;
  }
  
  if (gui) 
    { 
      init_curses(); 
      
      wborder(mainwin,0,0,0,0,0,0,0,0);
      getmaxyx(mainwin,y,x);
      
      mvprintw(0,(x/2)-11,"Nagraudio version %s",VERSION);
      mvprintw(2,2,"Sampling info : %d hz %d bits",DEC_FREQ,bits);
#ifndef ALSA
      mvprintw(4,2,"Input device  : OSS record");
      mvprintw(6,2,"Output device : %s",device);
#else
      mvprintw(4,2,"Input device  : ALSA record");
      mvprintw(6,2,"Output device : ALSA pcm0");
#endif
      mvprintw(8,2,"d) - Decoding      : %s",(decode)? "ON":"OFF");
      mvprintw(10,2,"a) - Auto decoding : %s",(auto_decode)? "ON":"OFF");
      mvprintw(12,2,"p) - Level of pre filter used  : %d %s",(pre_filter_level)? pre_filter_level/2+1:0,(pre_filter_level)? "":"(Disabled)");
      mvprintw(14,2,"o) - Level of post filter used : %d %s",(post_filter_level)? post_filter_level/2+1:0,(post_filter_level)? "":"(Disabled)");
      mvprintw(16,2,"g) - Ouput gain : x%d %s",1<<OUT_GAIN,(OUT_GAIN)? "":"(Disabled)");
      mvprintw(20,2,"q) - Quit");
      refresh();
    }
  else 
    {
      printf("Nagraudio version %s\n",VERSION);
      printf("Sampling %d hz %d bits\n\n",DEC_FREQ,bits);
      if (!use_config) printf("Ignoring configuration file\n");
      if (post_filter_level) 
	printf("Using post filter of level %d\n",post_filter_level/2+1);
      if (pre_filter_level)
	printf("Using pre filter of level %d\n",pre_filter_level/2+1);
      if (auto_decode) 
	printf("Automatic decoding enabled.\n");
      if (OUT_GAIN)
        printf("Using output gain of level %d (x%d)\n",OUT_GAIN,1<<OUT_GAIN);
    }
  
#ifndef ALSA
  if (bits==8) 
    do_audio_decode_8();
  else 
    do_audio_decode_44();
#else
  do_audio_decode_44();
#endif
  
  erase();
  refresh(); 
  endwin();
  puts("");
  puts("Thanx for use nagraudio :-)"); 
  puts("Look for last versions at http://asterix.uc3m.es/nagraudio");
  puts("");
  exit(0);
}
