/*
 * genera un suono di 3 secondi mono sui due auricolari, con assegnate 
 * frequenza,
 * ampiezza,  
 * precisione numerica
 * big (default per i file.cdr) o little endian
 * formato di uscita: (16bit big/little endian stereo PCM) 
 *
 *
 * Sergio Steffe' - Laboratorio Sperimentale di Matematica Computazionale
 * Dipartimento di Matematica - Universita' di Pisa - AA 2004-2005
 *  ultima modifica: 2005-05-19
 */

#include <stdio.h>
#include <math.h>
#include <unistd.h> /* per getopt */
#include <string.h>
#include <stdlib.h> /* per exit e return */
#include <ctype.h> /* per isprint */

/* prototipi C99 */
double round(double);
/* fine prototipi */

static void usage(char *command)
{
        fprintf(stderr,
"Usage: %s FILE [OPTION]... \n"
"-h,            help\n"
"-e,		little endian (default big endian)\n"
"-a amp		amplitude of the signal 0.0-1.0(default 1.0)\n"
"-f frequency	frequency of the signal (default 1000)\n"
"-b bitsi	significative bit 4-16 (default 8)\n"
"    writes 3 sec. of stereo sinusoidal signal, sampling rate 44100Hz\n"
	 ,command);
}

int main(argc,argv)
int argc;
char *argv[];

{
/* dichiarazioni      */
  FILE *cdrout, *fopen();
  char nomefile[256]; /* nome del file prodotto */
  char *nomecomando; /*nome del comando */
  int c; /* per il getopt */
  char *cvalue = NULL ; /* pre le stringhe delle opzioni */
  int i;  /* per i cicli */
  short int ii;   /* 2 bytes */
  char buf[256];  /* per la conversione little-endian big-endian */
  int wressize; /* buffer intero */
  double pi2; /* 2 pi greco */
  double maxint; /* max integer value 16 bit */
  double fsample; /* frequenza di campionamento */
  double freq; /* frequenza del suono generato */
  double ttime; /* durata del suono generato in secondi */
  int endian; /* little endian 1 - big endian 0 = default  */
  double amp; /* ampiezza del suono generato */
  double t, ds,sn; /* istante di tempo, ampiezza ds e sn */
  long ntot; /* numero totale campioni */
  int bitsi; /* numero bit significativi 4-16 */   
  int vbitsi;
/* fine dichiarazioni */
/* parametri fissi */
pi2=8*atan(1.0); 
fsample=44100.0;
maxint=32767.0;
ttime=3.0;
/* assegnazione parametri di default */
freq=1000.0;
amp=1.0;
bitsi=8;
endian=0;
nomecomando=argv[0];
if ((argc < 2)  || (argc > 9) ) {
                usage(nomecomando);
		exit(EXIT_FAILURE);
                };
/* getopt */

while ((c = getopt (argc, argv, "hef:a:b:")) != -1)
switch (c)
           {
	    case 'h':
		usage(nomecomando);
		exit(EXIT_FAILURE);
		break;
	    case 'e':
		endian =1; /* little endian */
		break;
	    case 'f':
		cvalue = optarg;
		/* printf ("cvalue = %s\n", cvalue);*/
		if( 1 != sscanf(cvalue,"%lg\n",&freq) ) {printf("parametro -f %s non valido\n",cvalue); exit(EXIT_FAILURE);}
		/* printf("frequenza = %g\n",freq);*/
	    	break; 
	    case 'a':
	    	cvalue = optarg;
		/* printf ("cvalue = %s\n", cvalue);*/	
		if( 1 != sscanf(cvalue,"%lg\n",&amp)) {printf("parametro -a %s non valido\n",cvalue); exit(EXIT_FAILURE);}
                /* printf("ampiezza = %g\n",amp);*/
                if((amp < 0.0)||(amp > 1.0)) {
			printf("parametro -a %f non valido\n",amp); 
			exit(EXIT_FAILURE);
			}
		break;
	    case 'b':
	    	cvalue = optarg;	
		/* printf ("cvalue = %s\n", cvalue);*/
		if( 1 != sscanf(cvalue,"%d",&bitsi)) {printf("parametro -b %s non valido\n",cvalue); exit(EXIT_FAILURE);}
                /* printf("bit significativi = %d\n",bitsi);*/
		break;	
	    case '?':
		if (isprint (optopt))
               fprintf (stderr, "Unknown option `-%c'.\n", optopt);
             else
		fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
             	exit(EXIT_FAILURE);
           default:
             abort ();
          } 
/* apri in scrittura il file.cdr */
if( argv[optind] != NULL) strcpy(nomefile,argv[optind]);

if ((cdrout = fopen(nomefile,"w")) == NULL) {
        printf("\n non posso aprire il file  %s \n",nomefile);
        exit(EXIT_FAILURE);
        };



/* sistemazione bit significativi tra 4 e 16 */
if (bitsi > 16) bitsi=16;
if (bitsi < 4) bitsi=4;
/* vbitsi=2**(16-bitsi) */
vbitsi=1;
for(i=0;i<16-bitsi;i++) vbitsi=vbitsi*2;


/* ttime secondi di suono */
ntot=ttime*fsample+0.5;

for(i=0;i<ntot;i++) {
 t=i/fsample;

/* canale destro */
 ds=maxint*amp*sin(t*pi2*freq);
 ii=round(ds); /* short int 2 bytes */
 ii = ii - (ii % vbitsi);
if (endian ==0)
	{
/* big endian: scambio dei due bytes */
 memcpy(buf,&ii,2);
 wressize=fwrite(&buf[1],1,1,cdrout);
 wressize=fwrite(buf,1,1,cdrout);
	}
else
	{
/* little endian */
memcpy(buf,&ii,2);
wressize=fwrite(buf,2,1,cdrout);
	}
/* canale sinistro */
 sn=maxint*amp*sin(t*pi2*freq);
 ii=round(sn); /* short int 2 bytes */
 ii = ii - (ii % vbitsi);
if (endian ==0)
	{
/* big endian: scambio dei due bytes */
 memcpy(buf,&ii,2);
 wressize=fwrite(&buf[1],1,1,cdrout);
 wressize=fwrite(buf,1,1,cdrout);
	}
else
	{
/* little endian */
memcpy(buf,&ii,2);
wressize=fwrite(buf,2,1,cdrout);
	}
 }

fclose(cdrout);

if (endian == 1) printf("scritto in %s %f sec (16 bit signed little endian short): \n    sinusoide di freq %f, amp %f, bits %d \n",nomefile,ttime,freq,amp,bitsi);
else
printf("scritto in %s %f sec (16 bit signed big endian short): \n    sinusoide di freq %f, amp %f, bits %d \n",nomefile,ttime,freq,amp,bitsi);

return EXIT_SUCCESS;
}
