/*
* wav9.c  - generate CUTS samples.
* usage: ..\tcc -run wav9.c 
* usage: gcc wav8.c && ./a.out && aplay test.wav
*
* usage: wav8 inputRawfilename outputRawFilename   
* 
*
*/

#include <stdio.h>
#include <assert.h>
#include <math.h>

#ifndef M_PI
#define M_PI 3.141592654
#endif

/*
*
* The 44100 samples need to be subsampled down to 8000.
* Use the method of adding absolute time
*
* for each CD_sample add 1/41000 to CD time
* when CD_time > 125us output a sample and subtract 125us
*
*/

/*

	[ source ] -- [ bytes to bits ] -- [ audio samples ]

    CUTS 
    * sent at 1200 baud or 300 baud:
    * 
    * '1' = 2400 Hz tone  - two cycle
    * '0' = 1200 Hz tone  - one cycle
    * 
    * sent at 300 baud:
    * 
    * '1' = 2400 Hz tone  - 8 cycles
    * '0' = 1200 Hz tone  - 4 cycles
    * 
* https://en.wikipedia.org/wiki/Kansas_City_standard#Kansas_City_symposium
* 
* Kansas City symposium

Wayne Green, who had just started Byte magazine, wanted all the manufacturers to get together and produce a single cassette standard. The site picked was Kansas City, Missouri. The two-day meeting was attended by 18 people who settled on a system based on Don Lancaster's design, published in Byte magazine's first issue. After the meeting, Lee Felsenstein (Processor Technology) and Harold Mauch (Percom) wrote the standard.

A cassette interface is similar to a modem connected to a serial port. The 1s and 0s from the serial port are converted to audio tones using audio frequency-shift keying (AFSK). A '0' bit is represented as four cycles of a 1200 Hz sine wave, and a '1' bit as eight cycles of 2400 Hz. This gives a data rate of 300 baud. Each frame starts with one start bit (a '0') followed by eight data bits (least significant bit first) followed by two stop bits ('1's). So each frame is 11 bits, for a data rate of  27 3⁄11 bytes per second.

The February 1976 issue of Byte had a report[5] on the symposium and the March issue featured two hardware examples by Don Lancaster[6] and Harold Mauch.[7] The 300 baud rate was reliable but slow. (The typical 8-kilobyte BASIC program took five minutes to load.) Most audio cassette circuits would support higher speeds.

According to Solomon, the efforts were unsuccessful, "Unfortunately, it didn't last long; before the month ended, everyone went back to his own tape standard and the recording confusion got worse."[4] 
*/

int acc_8k, acc_baud, vout;

FILE* wav_file_out;
FILE* wav_file_in;

void bit( int bit );
void ts( int freq);

/*
 *  UART input
 *   for each sample 
 *   look for edges
 *   When new edge work zero counter
 *   
 *   if 2400 / 8000 = 0.3  
 *   if 1200 / 8000 = 0.15 
 * 
 *   ----____----____----____
 * 
 *   look for edges:
 * 	   count to next edge
 *     emit result
 * 	
 * 	 once got start bit:-	
 *     when waiting for start
 *     when '0' to '1' edge start delay for 1.5 bits
 * 	   count samples
 * 	   
 *   for each sample 
 *     increment 
 *     
 *   wait of start
 * 	   wait 1.5 bits
 *     sample
 * 	   wait 1 bit
 *     sample
 * 	   wait 1 bit
 *     sample
 * 	   wait 1 bit
 *     sample
 * 	   wait 1 bit
 * 
 * 
 * 
 * 	
 */ 

#define IP_DIFF 100

#define IP_80_20 4
#define IP_80_24 3
#define IP_80_12 6

#define BAUD_RATE   (  300 )
#define SAMPLE_RATE ( 8000 )

//typdef enum ip_states = { IP_AWAIT_START, IP_STARTED };
#define IP_AWAIT_START 0
#define IP_STARTED 	   1

int ip_last, ip_inc, ip_cnt, ip_cnt_last, ip_cnt_last_last, ip_char, ip_char_bit ;  
int ip_state; /* AWAIT_START, STARTED */

char tx_char;	
	
int ts_ip_edge( int ip ){
  /* look for rising edge */
  int ip_delta;
  ip_delta = ip - ip_last;
  ip_last = ip;	
  if ( ( ip_delta ) < -100 )	{
	// printf("/");  
    return 1 ;
  }
  if ( ( ip_delta ) > 100 )	{
	// printf("/");  
    return 1 ;
  }

  // printf("-");  
  return 0;  
};

void ip_emit_char( char ip_char ){
  if( ip_char < 0 ){
	printf( "=%02X ",( 0x100+ip_char) );
  } else {
	printf( "=%02X ",( ip_char) );
  }	
  if ( tx_char != ip_char ) {
	  printf("Error:- =================================");
	  getchar();
  } 
};



int ts_ip( int ip ){
  int ip_edge;
  	
  // look for edge
  ip_edge = ts_ip_edge( ip );
  //printf("%c%c %3d %3d %5d bit: %3d \n", ip_edge+'.' ,  ip_state+'a', ip_cnt, ip_cnt_last, ip_inc, ip_char_bit   );  
  //printf("%c", ip_cnt_last   );  
  printf("%d", (ip_cnt_last+ip_cnt_last_last)   );  

  /* increment timer since last edge */
  ip_cnt++;  
  
  if ( ip_edge ){
	/* copy and zero timer  */	 
	ip_cnt_last_last = ip_cnt_last;
	ip_cnt_last = ip_cnt;
	ip_cnt 	    = 0     ;
	
  	if ( ip_state == IP_AWAIT_START ){ 	   
		
	  if ( (ip_cnt_last+ip_cnt_last_last) > 5  ) { /* found first cycle of ZERO */
	    /* start UART */	
	    printf(" S ");
	    ip_state    = IP_STARTED ;
	    /* resync timing - found stop bit, so step past*/
	    ip_inc      += -SAMPLE_RATE ; /* want 1.5 bits of delay to step past */
	    ip_inc      += +SAMPLE_RATE/8 ; /* want 1.5 bits of delay to step past */
	    ip_char_bit =    0;
	    ip_char     =    0;
      }
    } else {
	    ip_state    = IP_STARTED ;
    }
  }
  
  
  /* increment bit timer sample timer */
  /* 
   * t += 1/300 seconds 
   * 
   * which is 8000/300 samples = 80/3
   * 
   * if you increment ip_inc by baud, but knock back by 8000samples/sec on overflow
   *  
   * ip_inc += baud
   * on overflow 
   * ip_inc += -samples per second 
   * 
   * if baud = 1 then 8000 samples required
   * 
   * sample rate is 8000 samples per second 
   * to get 300 baud we need 1 / 300 baud * 8000 samples per second
   * /
   */ 

  /* bits sent 300 baud */
  
//ip_inc += 300;  /* baud */

  /*
   * UART code */

  ip_inc += BAUD_RATE;  /* baud */

  if ( ip_inc > 0 ){
    ip_inc	+= -SAMPLE_RATE ; /* knockback ip_inc by 8000 */
    
	ip_char_bit +=1;
	ip_char = ip_char >> 1; 
	  
    if ( (ip_cnt_last+ip_cnt_last_last)  < 6 ) { /* cnt suggests a 2400 Hz */
	  ip_char     += 128;  
    }  
    
    if ( ip_char_bit == 8 ){
		ip_emit_char( ip_char );
    }
    
    if ( ip_char_bit > 8 ){
		ip_state    = IP_AWAIT_START;
		ip_char_bit = 0 ;
		ip_char     = 0 ;
    }
  }
} 
 












void send_bit( int bit ){
  acc_baud += -SAMPLE_RATE;

  printf("\n!");  
  while( acc_baud < 0){ 
    //acc_baud += 2400;
    //acc_baud += 1200;
    //acc_baud += 300;
    acc_baud   += BAUD_RATE;
    if ( bit == 1 ){
      ts( 2400 );
    } else {
      ts( 1200 );
    }
  }
  printf("|");  
}


/* call this 8000 times a second*/
void ts( int freq){
  short buf[10];	
  acc_8k += freq;
  if ( acc_8k > 0 ){
    acc_8k += -(SAMPLE_RATE/2);
    vout = -vout;
  }
  // printf("%d",vout);
  buf[0] = vout*8192;
  if ( wav_file_out ){ 
    fwrite(&buf[0], sizeof( short ),1, wav_file_out); 
  }
  //if ( vout < 0 ) { printf("-"); } else { printf("+"); };

  /* pass samples through decoder */
  ts_ip( vout*8192 );

}
 
 
 
int main(int argc, char ** argv)
{ 
    int i,c,ch ;
    short buf[10];
    char  buf_ch[10];

   	FILE* wav_file;
   	FILE* wav_file_in;
    size_t got;
    
    if( argc < 2 ){ 
      printf("\nThis puts a wav header onto raw audio in 8000ms mono little endian\n usage: wav5 inputRawfilename outputWavFilename \n");  
    }
    char * ipFileName = "serialout.bin";
    char * opFileName = "serialout.raw";

    if( argc > 1 ){ ipFileName = argv[1]; }
    if( argc > 2 ){ opFileName = argv[2]; }  

    printf("Using: %s > %s \n",ipFileName,opFileName  );
    printf("Using: %s > %s \n",ipFileName,opFileName  );
    
    wav_file_out = fopen( opFileName, "wb+");
    wav_file_in  = fopen( ipFileName, "rb" );

	if ( ! wav_file_out  ){ printf( "error: output file ");    }
	if ( ! wav_file_in   ){ printf( "error: Input file ");     }

    vout     = 1;
    acc_baud = 1;
	ip_state = IP_AWAIT_START;
    ip_inc	+= 0;
    while(1){
	  got = fread( &buf_ch[0], sizeof( char ),1, wav_file_in );
  	  if( feof(wav_file_in) )
  	  { 
	    break ;
	  }
      ch 	  = buf_ch[0];
      tx_char = ch;
      
      /* debug print char */
      if( ch < 0 ){
	    printf("\n %02X= ",(0x100+ch) );	  
	  } else {
		printf("\n %02X= ", ch  );  
	  } 
      //for( i =0 ; i < 512; i++){
	  /* start bit */
	  send_bit( 0 );
      ch = ch & 0xff;
      tx_char = ch; 
      for( c = 0; c < 8 ; c++){
	    printf(":");
        send_bit( ch & 1 );
        ch = ch >> 1;
	  }
	  printf("#");
	  /* stop bits */
	  send_bit( 1 );
	  send_bit( 1 );
	  
	  send_bit( 1 );
	  send_bit( 1 );

/*
	  send_bit( 1 );
	  send_bit( 1 );	  
	  send_bit( 1 );
	  send_bit( 1 );
	  send_bit( 1 );
	  send_bit( 1 );
*/	  
    }
	if ( wav_file_in ) {	fclose( wav_file_in  );	}
	if ( wav_file_out ){	fclose( wav_file_out );	}
    return 0;
}

