module: read_write_audio_file
description: 
label_as_libsndfile_module: yes
timing_sensitivity: 
parameters:  int num_i, int num_o
inputs:  double in0,, double in1,
outputs:  double out0, double out1, double_interp clk, bool out_valid
classes:  SigGen clk_gen("square",1.0,Ts), EdgeDetect clk_edge()
static_variables:  SNDFILE *infile, SNDFILE *outfile, SF_INFO sfinfo, int BUF_LEN, 
                   double *in_buffer, double *out_buffer
                   int buf_count, int buf_size, int input_file_complete_flag
                   int num_channels
init:
double sample_rate, sample_period;
int num_frames, num_samples;
char in_filename[100], out_filename[100];


// memset(&sfinfo,0,sizeof(sfinfo));

// Open input audio file
snprintf(in_filename,100,"audio_in_%d.wav", num_i);
if ((infile = sf_open(in_filename, SFM_READ, &sfinfo)) == NULL)     
   {     
   printf("Error in 'read_write_audio_file':  cannot open input file '%s'\n", in_filename);
   exit(1) ;
   } 

sample_rate = (double) sfinfo.samplerate;
num_channels = sfinfo.channels;
num_frames = sfinfo.frames;
num_samples = num_frames*num_channels;

if (num_channels < 1 || num_channels > 2)
   {
   printf("Error in 'read_write_audio_file':  number of channels in\n");
   printf("   input audio file '%s' must be 1 or 2\n", in_filename);
   printf("   -> in this case, number of channels = %d\n", num_channels);
   sf_close(infile);
   exit(1) ;
   }

if (sample_rate < 1.0)
   {
   printf("Error in 'read_write_audio_file':  sample rate in\n");
   printf("   input audio file '%s' must be >= 1\n", in_filename);
   printf("   -> in this case, sample_rate = %5.3e\n", sample_rate);
   sf_close(infile);
   exit(1) ;
   }

sample_period = 1.0/sample_rate;

if (sample_period < 5.0*Ts)
   {
   printf("Error in 'read_write_audio_file':  1/Ts set in simulation file\n");
   printf("   must be > 5x the sample rate of the input audio file '%s'\n", in_filename);
   if (Ts > 1e-30)
      printf("   -> in this case, 1/Ts = %5.3e, sample_rate = %5.3e\n", 1.0/Ts, sample_rate);
   else
      printf("   -> in this case, Ts = %5.3e, sample_period = %5.3e\n", Ts, sample_period);
   printf("      (note that there are %d channels in input audio file '%s')\n", num_channels, in_filename);
   sf_close(infile);
   exit(1) ;
   }

clk_gen.set("square", sample_rate, Ts);

// Open output audio file
snprintf(out_filename,100,"audio_out_%d.wav", num_o); 
if ((outfile = sf_open(out_filename, SFM_WRITE, &sfinfo)) == NULL) 
   { 
   printf("Error 'read_write_audio_file':  cannot open output file '%s'\n", out_filename);
   exit(1);
   }


// create input and output buffers
// note that BUF_LEN must integer multiple of num_channels
BUF_LEN = 1024*num_channels;

in_buffer = (double *) calloc(BUF_LEN,sizeof(double));
if (in_buffer == NULL)
   {
    printf ("Error in 'read_write_audio_file': could not create double array of size '%d'\n", BUF_LEN);
    printf("  -> calloc call failed (out of memory) when creating in_buffer\n");
    exit(1);
   }

out_buffer = (double *) calloc(BUF_LEN,sizeof(double));
if (out_buffer == NULL)
   {
    printf ("Error in 'read_write_audio_file': could not create double array of size '%d'\n", BUF_LEN);
    printf("  -> calloc call failed (out of memory) when creating out_buffer\n");
    exit(1);
   }


buf_count = 0;
out_valid = 0;
out0 = 0.0;
out1 = 0.0;

buf_size = sf_read_double(infile, in_buffer, BUF_LEN);
if (buf_size <= 0)
   input_file_complete_flag = 1;
else
   input_file_complete_flag = 0;

end:
sf_close(infile);
sf_close(outfile);
free(in_buffer);
free(out_buffer);

code:

clk = clk_gen.inp(0.0);

if (clk_edge.inp(clk))
   {
   if (input_file_complete_flag == 0)
      {
      if (buf_count >= buf_size)
         {
          buf_count = 0;
          sf_write_double(outfile, out_buffer, buf_size);
          buf_size = sf_read_double(infile, in_buffer, BUF_LEN);
          if (buf_size <= 0)
              input_file_complete_flag = 1;
         }

      if (buf_count < buf_size)
         {
          out_valid = 1;
          if (num_channels == 1)
             {
              if (buf_count >= BUF_LEN)
                 {
                 printf ("Error in 'read_write_audio_file': buf_count has exceeded BUF_LEN\n");
                 printf("  -> buf_count = %d, BUF_LEN = %d\n", buf_count, BUF_LEN);
                 printf("  ---->  this should never happen! ??\n");
                 exit(1);
                 }
              out0 = in_buffer[buf_count];
              out1 = 0.0;
              if (in0 > 1.0)
                 out_buffer[buf_count] = 1.0;
              else if (in0 < -1.0)
                 out_buffer[buf_count] = -1.0;
              else
                 out_buffer[buf_count] = in0;
              buf_count++;
             }
          else if (num_channels == 2)
             {
              if (buf_count >= BUF_LEN)
                 {
                 printf ("Error in 'read_write_audio_file': buf_count has exceeded BUF_LEN\n");
                 printf("  -> buf_count = %d, BUF_LEN = %d\n", buf_count, BUF_LEN);
                 printf("  ---->  this should never happen! ??\n");
                 exit(1);
                 }
              out0 = in_buffer[buf_count];
              if (in0 > 1.0)
                 out_buffer[buf_count] = 1.0;
              else if (in0 < -1.0)
                 out_buffer[buf_count] = -1.0;
              else
                 out_buffer[buf_count] = in0;
              buf_count++;

              if (buf_count >= BUF_LEN)
                 {
                 printf ("Error in 'read_write_audio_file': buf_count has exceeded BUF_LEN\n");
                 printf("  -> buf_count = %d, BUF_LEN = %d\n", buf_count, BUF_LEN);
                 printf("  ---->  this should never happen! ??\n");
                 exit(1);
                 }
              out1 = in_buffer[buf_count];
              if (in1 > 1.0)
                 out_buffer[buf_count] = 1.0;
              else if (in1 < -1.0)
                 out_buffer[buf_count] = -1.0;
              else
                 out_buffer[buf_count] = in1;
              buf_count++;
            }
         }
      }
   else
      {
      out0 = 0.0;
      out1 = 0.0;
      out_valid = 0;
      }
   }
  
