Hello, I'm new in Linux and ALSA programming, I need to write raw audio file from ALSA audio buffer. I'm using fwrite to write raw audio data from buffer but the ouput file contain no data. Please help!
This program is used to apply real-time audio panning from left to right and right to left
This is the code:
Code:
/* %: gcc latproc.c -o latproc -lfftw3f -lasound -lrt -ldl -lm */


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sched.h>
#include <errno.h>
#include <getopt.h>
#include <alsa/asoundlib.h>
#include <sys/time.h>
#include <math.h>
#include <math.h>


char *pdevice = "hw:1,0";
char *cdevice = "hw:1,0";
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
int rate = 48000;
int channels = 2;
int buffer_size = 0;            /* auto */
int period_size = 0;            /* auto */
int latency_min ;           /* in frames / 2 */
/* latency_min = 32, 64, 128,...., 1024, 2048, 8192, 16384, 32768 */
int latency_max = 32768;         /* in frames / 2 */
int block = 1;                  /* block mode */
int use_poll = 0;
int resample = 1;
unsigned long loop_limit;
snd_output_t *output = NULL;


int doublecomp();
int floatcomp();


///////


double sine_array[480000];
int last_position = 0;


///////


int setparams_stream(snd_pcm_t *handle,
             snd_pcm_hw_params_t *params,
             const char *id)
{
  int err;
  unsigned int rrate;
  err = snd_pcm_hw_params_any(handle, params);
  if (err < 0) {
    printf("Broken configuration for %s PCM: no configurations available: %s\n", snd_strerror(err), id);
    return err;
  }
  err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
  if (err < 0) {
    printf("Resample setup failed for %s (val %i): %s\n", id, resample, snd_strerror(err));
    return err;
  }
  err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
  if (err < 0) {
    printf("Access type not available for %s: %s\n", id, snd_strerror(err));
    return err;
  }
  err = snd_pcm_hw_params_set_format(handle, params, format);
  if (err < 0) {
    printf("Sample format not available for %s: %s\n", id, snd_strerror(err));
    return err;
  }
  err = snd_pcm_hw_params_set_channels(handle, params, channels);
  if (err < 0) {
    printf("Channels count (%i) not available for %s: %s\n", channels, id, snd_strerror(err));
    return err;
  }
  rrate = rate;
  err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
  if (err < 0) {
    printf("Rate %iHz not available for %s: %s\n", rate, id, snd_strerror(err));
    return err;
  }
  if ((int)rrate != rate) {
    printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
    return -EINVAL;
  }
  return 0;
}
int setparams_bufsize(snd_pcm_t *handle,
              snd_pcm_hw_params_t *params,
              snd_pcm_hw_params_t *tparams,
              snd_pcm_uframes_t bufsize,
              const char *id)
{
  int err;
  snd_pcm_uframes_t periodsize;
  snd_pcm_hw_params_copy(params, tparams);
  periodsize = bufsize * 2;
  err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &periodsize);
  if (err < 0) {
    printf("Unable to set buffer size %li for %s: %s\n", bufsize * 2, id, snd_strerror(err));
    return err;
  }
  if (period_size > 0)
    periodsize = period_size;
  else
    periodsize /= 2;
  err = snd_pcm_hw_params_set_period_size_near(handle, params, &periodsize, 0);
  if (err < 0) {
    printf("Unable to set period size %li for %s: %s\n", periodsize, id, snd_strerror(err));
    return err;
  }
  return 0;
}
int setparams_set(snd_pcm_t *handle,
          snd_pcm_hw_params_t *params,
          snd_pcm_sw_params_t *swparams,
          const char *id)
{
  int err;
  snd_pcm_uframes_t val;
  err = snd_pcm_hw_params(handle, params);
  if (err < 0) {
    printf("Unable to set hw params for %s: %s\n", id, snd_strerror(err));
    return err;
  }
  err = snd_pcm_sw_params_current(handle, swparams);
  if (err < 0) {
    printf("Unable to determine current swparams for %s: %s\n", id, snd_strerror(err));
    return err;
  }
  err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0x7fffffff);
  if (err < 0) {
    printf("Unable to set start threshold mode for %s: %s\n", id, snd_strerror(err));
    return err;
  }
  if (!block)
    val = 4;
  else
    snd_pcm_hw_params_get_period_size(params, &val, NULL);
  err = snd_pcm_sw_params_set_avail_min(handle, swparams, val);
  if (err < 0) {
    printf("Unable to set avail min for %s: %s\n", id, snd_strerror(err));
    return err;
  }
  err = snd_pcm_sw_params(handle, swparams);
  if (err < 0) {
    printf("Unable to set sw params for %s: %s\n", id, snd_strerror(err));
    return err;
  }
  return 0;
}
int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int *bufsize)
{
  int err, last_bufsize = *bufsize;
  snd_pcm_hw_params_t *pt_params, *ct_params;     /* templates with rate, format and channels */
  snd_pcm_hw_params_t *p_params, *c_params;
  snd_pcm_sw_params_t *p_swparams, *c_swparams;
  snd_pcm_uframes_t p_size, c_size, p_psize, c_psize;
  unsigned int p_time, c_time;
  unsigned int val;
  snd_pcm_hw_params_alloca(&p_params);
  snd_pcm_hw_params_alloca(&c_params);
  snd_pcm_hw_params_alloca(&pt_params);
  snd_pcm_hw_params_alloca(&ct_params);
  snd_pcm_sw_params_alloca(&p_swparams);
  snd_pcm_sw_params_alloca(&c_swparams);
  if ((err = setparams_stream(phandle, pt_params, "playback")) < 0) {
    printf("Unable to set parameters for playback stream: %s\n", snd_strerror(err));
    exit(0);
  }
  if ((err = setparams_stream(chandle, ct_params, "capture")) < 0) {
    printf("Unable to set parameters for playback stream: %s\n", snd_strerror(err));
    exit(0);
  }
  if (buffer_size > 0) {
    *bufsize = buffer_size;
    goto __set_it;
  }
 __again:
  if (buffer_size > 0)
    return -1;
  if (last_bufsize == *bufsize)
    *bufsize += 4;
  last_bufsize = *bufsize;
  if (*bufsize > latency_max)
    return -1;
 __set_it:
  if ((err = setparams_bufsize(phandle, p_params, pt_params, *bufsize, "playback")) < 0) {
    printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
    exit(0);
  }
  if ((err = setparams_bufsize(chandle, c_params, ct_params, *bufsize, "capture")) < 0) {
    printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
    exit(0);
  }
  snd_pcm_hw_params_get_period_size(p_params, &p_psize, NULL);
  if (p_psize > (unsigned int)*bufsize)
    *bufsize = p_psize;
  snd_pcm_hw_params_get_period_size(c_params, &c_psize, NULL);
  if (c_psize > (unsigned int)*bufsize)
    *bufsize = c_psize;
  snd_pcm_hw_params_get_period_time(p_params, &p_time, NULL);
  snd_pcm_hw_params_get_period_time(c_params, &c_time, NULL);
  if (p_time != c_time)
    goto __again;
  snd_pcm_hw_params_get_buffer_size(p_params, &p_size);
  if (p_psize * 2 < p_size) {
    snd_pcm_hw_params_get_periods_min(p_params, &val, NULL);
    if (val > 2) {
      printf("playback device does not support 2 periods per buffer\n");
      exit(0);
    }
    goto __again;
  }
  snd_pcm_hw_params_get_buffer_size(c_params, &c_size);
  if (c_psize * 2 < c_size) {
    snd_pcm_hw_params_get_periods_min(c_params, &val, NULL);
    if (val > 2 ) {
      printf("capture device does not support 2 periods per buffer\n");
      exit(0);
    }
    goto __again;
  }
  if ((err = setparams_set(phandle, p_params, p_swparams, "playback")) < 0) {
    printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
    exit(0);
  }
  if ((err = setparams_set(chandle, c_params, c_swparams, "capture")) < 0) {
    printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
    exit(0);
  }
  if ((err = snd_pcm_prepare(phandle)) < 0) {
    printf("Prepare error: %s\n", snd_strerror(err));
    exit(0);
  }
  snd_pcm_dump(phandle, output);
  snd_pcm_dump(chandle, output);
  fflush(stdout);
  return 0;
}


long readbuf(snd_pcm_t *handle, short *buf, long len, size_t *frames, size_t *max)
{
  long r=0,hitung=0;


    int frame_bytes = (snd_pcm_format_width(format) / 8) * channels;
    do {
    printf("hitung= %ld; len= %ld; r= %ld\n",hitung++,len,r);
      r = snd_pcm_readi(handle, buf, len);
      if (r > 0) {
    buf += r * frame_bytes;
    len -= r;
    *frames += r;
    if ((long)*max < r)
      *max = r;


      }
    printf("hitung= %ld; len= %ld; r= %ld\n",hitung++,len,r);




    } while (r >= 1 && len > 0);




   return r;
}


long writebuf(snd_pcm_t *handle, short *buf, long len, size_t *frames)
{
  long r;
  while (len > 0) {
    r = snd_pcm_writei(handle, buf, len);
    if (r == -EAGAIN)
      continue;
    if (r < 0)
      return r;
    buf += r * 4;
    len -= r;
    *frames += r;
  }
  return 0;
}




void pan_v2(short *buffer, int r, double a) {
  int i;
  int latency_max = 32768;
  int buflen=latency_max/32;        //default: 32 for latency 512
  double depth = 1.0, xbuf;
  double LVOL = 0;
  double RVOL = 0;


  LVOL = 1-a; //Modulator signal value 0 = center panning
  RVOL = 1+a; //Modulator signal value 0 = center panning


  for (i=0;i<buflen;i++)    {


      if(i%2==0)     /* Left channel */ {
      xbuf= (double)buffer[i]*(double)(LVOL);
      buffer[i]=(int16_t)(xbuf);
    }
      else          /* Right channel */ {
      xbuf= (double)buffer[i]*(double)(RVOL);
      buffer[i]=(int16_t)(xbuf);
    }
  }
}




int main()
{
      snd_pcm_t *phandle, *chandle;
      short *buffer;
      int err, latency, morehelp;
      snd_timestamp_t p_tstamp, c_tstamp;
      ssize_t r;
      size_t frames_in, frames_out, in_max;
      int effect = 0;
      morehelp = 0;


//////////////////////////////////////////////// Generating the Sine Array
double target_frequency = 0.5; //Target Frequency
double converted_frequency = 250.0*target_frequency; //for some reason 1 Hz = 250
double dpi;
int sampling_rate = 48000.0;
double pi = M_PI;
double temp_value = 0;
dpi = (2.0*pi)*(converted_frequency/sampling_rate);
for(int i=i;i<48000;i++) {
    temp_value = (double)sin(dpi*(double)i);
    sine_array[i] = (double)temp_value;
}
//////////////////////////////////////////////////////////////////////////
  printf("\n\n");
  printf(
     "Tip #1 (usable latency with large periods, non-blocking mode, good CPU usage,\n"
     "        superb xrun prevention):\n"
     "  latency -m 8192 -M 8192 -t 1 -p\n"
     "Tip #2 (superb latency, non-blocking mode, but heavy CPU usage):\n"
     "  latency -m 128 -M 128\n"
     );


  printf("\n");
  latency_min = 512; //Fixed latency setting


      err = snd_output_stdio_attach(&output, stdout, 0);
      if (err < 0) {
        printf("Output failed: %s\n", snd_strerror(err));
        return 0;
      }


      latency = latency_min - 4;


      /*--------------------------------- penting ----------------------*/
      buffer = malloc((latency_max * snd_pcm_format_width(format) / 8) * 2);
      /*----------------------------------------------------------------*/


      printf("Playback device is %s\n", pdevice);
      printf("Capture device is %s\n", cdevice);
      printf("Parameters are %iHz, %s, %i channels, %s mode\n",
         rate, snd_pcm_format_name(format), channels, block ? "blocking" : "non-blocking");
      printf("Poll mode: %s\n", use_poll ? "yes" : "no");


      if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, block ? 0 : SND_PCM_NONBLOCK)) < 0) {
        printf("Playback open error: %s\n", snd_strerror(err));
        return 0;
      }
      if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE, block ? 0 : SND_PCM_NONBLOCK)) < 0) {
        printf("Record open error: %s\n", snd_strerror(err));
        return 0;
      }


      while (1) {
        frames_in = frames_out = 0;
        if (setparams(phandle, chandle, &latency) < 0)
          break;
        if ((err = snd_pcm_link(chandle, phandle)) < 0) {
          printf("Streams link error: %s\n", snd_strerror(err));
          exit(0);
        }
        if (snd_pcm_format_set_silence(format, buffer, latency*channels) < 0) {
          fprintf(stderr, "silence error\n");
          break;
        }
        if (writebuf(phandle, buffer, latency, &frames_out) < 0) {
          fprintf(stderr, "write error\n");
          break;
        }
        if (writebuf(phandle, buffer, latency, &frames_out) < 0) {
          fprintf(stderr, "write error\n");
          break;
        }
        if ((err = snd_pcm_start(chandle)) < 0) {
          printf("Go error: %s\n", snd_strerror(err));
          exit(0);
        }
        in_max = 0;


        int lp = 0;
        double a = 0;
        double depth = 1.0;


        short audio_buffer_out[480000] = {0};
        FILE *f;


        while (1) {
          r = readbuf(chandle, buffer, latency, &frames_in, &in_max);  /* capture audio from mic */
          a = sine_array[lp];
          pan_v2(buffer,r,a); //Apply Panning
          audio_buffer_out[lp] = buffer; //Save data from ALSA buffer
          writebuf(phandle, buffer, r, &frames_out); //output panned audio from ALSA buffer
          if(lp == 1000) {
            printf("\nWriting to raw file\n");
            f = fopen("./pan_output.raw","wb");
              if(f==NULL) {
                printf("\nfile error\n");
                exit(1);
              }
            fwrite(&audio_buffer_out,sizeof(short),1,f);
            fclose(f);
            printf("Done\n");
            exit(0);
          }
          lp++; //Modulator Signal Array Index
          printf("Sine Array Index: %d\n",lp);


        }
      printf("Hardware sync\n");
      snd_pcm_drop(chandle);
      snd_pcm_nonblock(phandle, 0);
      snd_pcm_drain(phandle);
      snd_pcm_nonblock(phandle, !block ? 1 : 0);


      snd_pcm_unlink(chandle);
      snd_pcm_hw_free(phandle);
      snd_pcm_hw_free(chandle);
      }
      snd_pcm_close(phandle);
      snd_pcm_close(chandle);
      return 0;
}