Difference between revisions of "Упражнение 7. Аудио контролер"

From Ilianko
Line 14: Line 14:
  
 
libasound2-dev
 
libasound2-dev
 
 
<code><pre>
 
<code><pre>
#include <stdio.h>
+
#include <stdio.h>  
#include <stdlib.h>
+
#include <stdlib.h>
 +
#include <string.h>
 +
#include <errno.h>  
 
#include <alsa/asoundlib.h>
 
#include <alsa/asoundlib.h>
     
+
#include <math.h>
int main (int argc, char *argv[])
+
{
+
static char *device = "hw:0";                    /* playback device */
  /* Handle for the PCM device */  
+
static snd_pcm_format_t format = SND_PCM_FORMAT_S16;    /* sample format */
  snd_pcm_t *pcm_handle;        
+
static unsigned int rate = 44100;                      /* stream rate */
 +
static unsigned int channels = 2;                      /* count of channels */
 +
static unsigned int buffer_time = 500000;              /* ring buffer length in us */
 +
static unsigned int period_time = 100000;              /* period time in us */
 +
static double freq = 1000;                              /* sinusoidal wave frequency in Hz */
 +
static int verbose = 0;                        /* verbose flag */
 +
static int resample = 1;                                /* enable alsa-lib resampling */  
 +
 +
static snd_pcm_sframes_t buffer_size;
 +
static snd_pcm_sframes_t period_size;
 +
static snd_output_t *output = NULL;  
  
  /* Playback stream */
+
static void generate_sine(const snd_pcm_channel_area_t *areas, 
  snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
+
                          snd_pcm_uframes_t offset,
 
+
                          int count, double *_phase)
  /* This structure contains information about    */
+
{
  /* the hardware and can be used to specify the */    
+
        static double max_phase = 2. * M_PI;
  /* configuration to be used for the PCM stream. */  
+
        double phase = *_phase;
  snd_pcm_hw_params_t *hwparams;
+
       
 
+
      /* generate secret number: */
 
+
        double step = max_phase*freq/(double)rate;
  /* Name of the PCM device, like plughw:0,0          */
+
       
    /* The first number is the number of the soundcard, */
+
        double res;
    /* the second number is the number of the device*/
+
        unsigned char *samples[channels], *tmp;
    char *pcm_name;
+
       
 
+
        int steps[channels];  
  /* Init pcm_name. Of course, later you */
+
        unsigned int chn, byte;
    /* will make this configurable ;-)     */
+
       
  pcm_name = strdup("default");
+
        int ires;
 +
        unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1;
 +
        int bps = snd_pcm_format_width(format) / 8;  /* bytes per sample */  
 +
       
 +
        /* verify and prepare the contents of areas */
 +
        for (chn = 0; chn < channels; chn++) {
 +
                if ((areas[chn].first % 8) != 0) {
 +
                        printf("areas[%i].first == %i, aborting...\n", chn, areas[chn].first);
 +
                        exit(EXIT_FAILURE);
 +
                }
 +
                samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
 +
                if ((areas[chn].step % 16) != 0) {
 +
                        printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step);
 +
                        exit(EXIT_FAILURE);
 +
                }
 +
                steps[chn] = areas[chn].step / 8;
 +
                samples[chn] += offset * steps[chn];
 +
        }
 +
        /* fill the channel areas */  
 +
        while (count-- > 0) {
 +
                res = sin(phase) *sin(phase) * maxval;
 +
                ires = res;
 +
                tmp = (unsigned char *)(&ires);
 +
                for (chn = 0; chn < channels; chn++) {
 +
                        for (byte = 0; byte < (unsigned int)bps; byte++)
 +
                                *(samples[chn] + byte) = tmp[byte];
 +
                        samples[chn] += steps[chn];
 +
                }
 +
                phase += step;
 +
                if (phase >= max_phase)
 +
                        phase -= max_phase;
 +
        }
 +
        *_phase = phase;
 +
}
 +
 +
static int set_hwparams(snd_pcm_t *handle,
 +
                        snd_pcm_hw_params_t *params,
 +
                        snd_pcm_access_t access)
 +
{
 +
        unsigned int rrate;  
 +
        snd_pcm_uframes_t size;
 +
        int err, dir;
 +
 +
        /* choose all parameters */
 +
        snd_pcm_hw_params_any(handle, params);
 +
        /* set hardware resampling */
 +
        snd_pcm_hw_params_set_rate_resample(handle, params, resample);
 +
        /* set the interleaved read/write format */
 +
        err = snd_pcm_hw_params_set_access(handle, params, access);
 +
        /* set the sample format */  
 +
        err = snd_pcm_hw_params_set_format(handle, params, format);
 +
        /* set the count of channels */
 +
        err = snd_pcm_hw_params_set_channels(handle, params, channels);
 +
        /* set the stream rate */
 +
        rrate = rate;
 +
        err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
 +
        if (err < 0) {
 +
                printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
 +
                return err;
 +
        }
 +
        if (rrate != rate) {
 +
                printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
 +
                return -EINVAL;
 +
        }
 +
        /* set the buffer time */  
 +
        snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
 +
        snd_pcm_hw_params_get_buffer_size(params, &size);
 +
       
 +
        buffer_size = size;
 +
        /* set the period time */
 +
        err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
 +
        if (err < 0) {
 +
                printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
 +
                return err;
 +
        }
 +
        err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
 +
        if (err < 0) {
 +
                printf("Unable to get period size for playback: %s\n", snd_strerror(err));
 +
                return err;
 +
        }
 +
        period_size = size;
 +
        /* write the parameters to device */  
 +
        err = snd_pcm_hw_params(handle, params);
 +
        if (err < 0) {
 +
                printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
 +
                return err;
 +
        }
 +
        return 0;
 +
}
 +
 +
static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
 +
{
 +
        /* get the current swparams */
 +
        snd_pcm_sw_params_current(handle, swparams);  
 +
        /* start the transfer when the buffer is almost full: */
 +
        /* (buffer_size / avail_min) * avail_min */  
 +
        snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size);  
 +
        /* allow the transfer when at least period_size samples can be processed */
 +
        snd_pcm_sw_params_set_avail_min(handle, swparams, period_size);
 +
        /* write the parameters to the playback device */  
 +
        snd_pcm_sw_params(handle, swparams);  
 +
        return 0;
 +
}
 +
 +
/*
 +
*  Underrun and suspend recovery
 +
*/
 
    
 
    
    /* Allocate the snd_pcm_hw_params_t structure on the stack. */
+
static int xrun_recovery(snd_pcm_t *handle, int err)
    snd_pcm_hw_params_alloca(&hwparams);
+
{
 +
        if (err == -EPIPE) {    /* under-run */
 +
                err = snd_pcm_prepare(handle);
 +
                if (err < 0)
 +
                        printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
 +
                return 0;
 +
        } else if (err == -ESTRPIPE) {
 +
                while ((err = snd_pcm_resume(handle)) == -EAGAIN)
 +
                        sleep(1);      /* wait until the suspend flag is released */
 +
                if (err < 0) {
 +
                        err = snd_pcm_prepare(handle);
 +
                        if (err < 0)
 +
                                printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
 +
                }
 +
                return 0;
 +
        }
 +
        return err;
 +
}
 +
 +
/*
 +
*  Transfer method - write only
 +
*/  
 +
 +
static int write_loop(snd_pcm_t *handle,
 +
                      signed short *samples,
 +
                      snd_pcm_channel_area_t *areas)
 +
{
 +
        double phase = 0;
 +
        signed short *ptr;
 +
        int err, cptr;
 +
 +
        while (1) {
 +
                generate_sine(areas, 0, period_size, &phase);
 +
                ptr = samples;
 +
                cptr = period_size;
 +
                while (cptr > 0) {
 +
                        err = snd_pcm_writei(handle, ptr, cptr);
 +
                        if (err == -EAGAIN)
 +
                                continue;
 +
                        if (err < 0) {
 +
                                if (xrun_recovery(handle, err) < 0) {
 +
                                        printf("Write error: %s\n", snd_strerror(err));
 +
                                        exit(EXIT_FAILURE);  
 +
                                }
 +
                                break;  /* skip one period */
 +
                        }
 +
                        ptr += err * channels;
 +
                        cptr -= err;
 +
                }
 +
        }
 +
}
 
    
 
    
    /* Open PCM. The last parameter of this function is the mode. */
+
int main(int argc, char *argv[])
    /* If this is set to 0, the standard mode is used. Possible  */
+
{
    /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.      */
+
srand(time(NULL));
    /* If SND_PCM_NONBLOCK is used, read / write access to the    */
+
        snd_pcm_t *handle;  
    /* PCM device will return immediately. If SND_PCM_ASYNC is    */
+
        snd_pcm_hw_params_t *hwparams;  
    /* specified, SIGIO will be emitted whenever a period has    */
+
        snd_pcm_sw_params_t *swparams;  
    /* been completely processed by the soundcard.                */
+
        signed short *samples;  
    if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
+
        unsigned int chn;  
      fprintf(stderr, "Error opening PCM device %s\n", pcm_name);
+
        snd_pcm_channel_area_t *areas;  
      return(-1);
+
   
    }
+
        snd_pcm_hw_params_alloca(&hwparams);  
   
+
        snd_pcm_sw_params_alloca(&swparams);  
   
+
    /* Init hwparams with full configuration space */
+
    if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
+
         if ( snd_output_stdio_attach(&output, stdout, 0)){  
      fprintf(stderr, "Can not configure this PCM device.\n");
+
                printf("Output failed: %s\n", snd_strerror(0));  
      return(-1);
+
                return 0;  
    }
+
        }  
   
+
   
+
        printf("Playback device is %s\n", device);  
   
+
        printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);  
   
+
        printf("Sine wave rate is %.4fHz\n", freq);  
   
+
     
    unsigned int rate = 44100; /* Sample rate */
+
        snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0);
    unsigned int exact_rate;   /* Sample rate returned by */
+
         set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
                      /* snd_pcm_hw_params_set_rate_near */
+
         set_swparams(handle, swparams);
    int dir;         /* exact_rate == rate --> dir = 0 */
 
                      /* exact_rate < rate --> dir = -1 */
 
                      /* exact_rate > rate  --> dir = 1 */
 
    int periods = 2;      /* Number of periods */
 
    snd_pcm_uframes_t periodsize = 512; /* Periodsize (bytes) */
 
   
 
    /* Set sample format */
 
    if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
 
      fprintf(stderr, "Error setting format.\n");
 
      return(-1);
 
    }
 
   
 
    /* Set sample rate. If the exact rate is not supported */
 
    /* by the hardware, use nearest possible rate.         */
 
    exact_rate = rate;
 
   
 
    if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0) < 0) {
 
      fprintf(stderr, "Error setting rate.\n");
 
      return(-1);
 
    }
 
   
 
    if (rate != exact_rate) {
 
      fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n ==> Using %d Hz instead.\n", rate, exact_rate);
 
    }
 
   
 
    /* Set number of channels */
 
    if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) {
 
      fprintf(stderr, "Error setting channels.\n");
 
      return(-1);
 
    }
 
 
 
    /* Set number of periods. Periods used to be called fragments.
 
    if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0) {
 
      fprintf(stderr, "Error setting periods.\n");
 
      return(-1);
 
    }*/
 
   
 
   
 
    /* Set buffer size (in frames). The resulting latency is given by */
 
    /* latency = periodsize * periods / (rate * bytes_per_frame)    */
 
    if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (periodsize * periods)>>2) < 0) {
 
      fprintf(stderr, "Error setting buffersize.\n");
 
      return(-1);
 
    }
 
   
 
    /* Apply HW parameter settings to */
 
    /* PCM device and prepare device  */
 
    if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) {
 
      fprintf(stderr, "Error setting HW params.\n");
 
      return(-1);
 
    }
 
   
 
   
 
    /* Write num_frames frames from buffer data to    */
 
    /* the PCM device pointed to by pcm_handle.      */
 
    /* Returns the number of frames actually written. */
 
    //  snd_pcm_sframes_t snd_pcm_writei(pcm_handle, data, num_frames);
 
   
 
    unsigned char *data;
 
    int pcmreturn, l1, l2;
 
    short s1, s2, s3, s4;
 
    int frames;
 
  //  int num_frames= 100;
 
 
 
    data = (unsigned char *)malloc(periodsize);
 
    frames = periodsize >> 3;
 
    for(l1 = 0; l1 < 10000; l1++) {
 
     
 
      for(l2 = 0; l2 < frames; l2++) {
 
       
 
        s1 = (l2 % 64) * 100 - 5000;
 
         s2 = (l2 % 128) * 100 - 5000;
 
         s3 = (l2 % 192) * 100 - 5000; 
 
        s4 = (l2 % 256) * 100 - 5000;   
 
       
 
        data[8*l2] = (unsigned char)s1;
 
        data[8*l2+1] = s1 >> 8;
 
        data[8*l2+2] = (unsigned char)s2;
 
        data[8*l2+3] = s2 >> 8;
 
 
          
 
          
         data[8*l2+4] = (unsigned char)s4;
+
         if (verbose > 0)  
        data[8*l2+5] = s3 >> 8;
+
                snd_pcm_dump(handle, output);  
        data[8*l2+6] = (unsigned char)s3;
+
         data[8*l2+7] = s4 >> 8;
+
         samples = malloc((period_size * channels * snd_pcm_format_width(format)) / 8);
     
+
         if (samples == NULL) {
      }
+
                printf("No enough memory\n");  
      while ((pcmreturn = snd_pcm_writei(pcm_handle, data, frames)) < 0) {
+
                exit(EXIT_FAILURE);
         snd_pcm_prepare(pcm_handle);
+
        }  
        fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
+
       
      }
+
        areas = calloc(channels, sizeof(snd_pcm_channel_area_t));  
    }
+
        if (areas == NULL) {
    /*
+
                printf("No enough memory\n");  
   
+
                exit(EXIT_FAILURE);  
    unsigned char *data;
+
        }
    int pcmreturn, l1, l2;
+
        for (chn = 0; chn < channels; chn++) {  
    short s1, s2;
+
                areas[chn].addr = samples;  
    int frames;
+
                areas[chn].first = chn * snd_pcm_format_width(format);  
 
+
                areas[chn].step = channels * snd_pcm_format_width(format);  
    data = (unsigned char *)malloc(periodsize);
+
         }
    frames = periodsize >> 2;
+
    for(l1 = 0; l1 < 10000; l1++) {
+
         write_loop(handle, samples, areas);  
      for(l2 = 0; l2 < frames; l2++) {
+
 
        s1 = (l2 % 128) * 100 - 5000; 
+
        s2 = (l2 % 256) * 100 - 5000;
+
        free(areas);
        data[4*l2] = (unsigned char)s1;
+
         free(samples);  
         data[4*l2+1] = s1 >> 8;
+
         snd_pcm_close(handle);  
         data[4*l2+2] = (unsigned char)s2;
+
        return 0;  
        data[4*l2+3] = s2 >> 8;
+
}</pre></code>
      }
 
      while ((pcmreturn = snd_pcm_writei(pcm_handle, data, frames)) < 0) {
 
         snd_pcm_prepare(pcm_handle);
 
         fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
 
      }
 
    }*/
 
  return 0;
 
}
 
 
 
</pre></code>
 
 
 
  

Revision as of 19:46, 27 April 2011

Цел на упражнението

Запознаване със средствата за работа със звук.

Alsa Advanced Linux Sound Architecture Състои се от набор от драйвери, API функции и инструменти.

принципна схема на работа на аудио проложение

отваряне на интерфейса за запис или възпроизвеждане задаване на параметрите на хардуера (тип на достъп, формат на данните, канали, честота на семплиране ...) докато има данни: прихващане на PCM данни или възпроизвеждане на PCM данни затваряне на интерфейса

libasound2-dev

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <alsa/asoundlib.h>
#include <math.h> 
 
static char *device = "hw:0";                     /* playback device */ 
static snd_pcm_format_t format = SND_PCM_FORMAT_S16;    /* sample format */ 
static unsigned int rate = 44100;                       /* stream rate */ 
static unsigned int channels = 2;                       /* count of channels */ 
static unsigned int buffer_time = 500000;               /* ring buffer length in us */ 
static unsigned int period_time = 100000;               /* period time in us */ 
static double freq = 1000;                               /* sinusoidal wave frequency in Hz */ 
static int verbose = 0;                         /* verbose flag */ 
static int resample = 1;                                /* enable alsa-lib resampling */ 
 
static snd_pcm_sframes_t buffer_size; 
static snd_pcm_sframes_t period_size; 
static snd_output_t *output = NULL; 

static void generate_sine(const snd_pcm_channel_area_t *areas,  
                          snd_pcm_uframes_t offset, 
                          int count, double *_phase) 
{ 
        static double max_phase = 2. * M_PI; 
        double phase = *_phase;
        
       /* generate secret number: */
        double step = max_phase*freq/(double)rate; 
        
        double res; 
        unsigned char *samples[channels], *tmp; 
        
        int steps[channels]; 
        unsigned int chn, byte; 
        
        int ires; 
        unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1; 
        int bps = snd_pcm_format_width(format) / 8;  /* bytes per sample */ 
         
        /* verify and prepare the contents of areas */ 
        for (chn = 0; chn < channels; chn++) { 
                if ((areas[chn].first % 8) != 0) { 
                        printf("areas[%i].first == %i, aborting...\n", chn, areas[chn].first); 
                        exit(EXIT_FAILURE); 
                } 
                samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8)); 
                if ((areas[chn].step % 16) != 0) { 
                        printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step); 
                        exit(EXIT_FAILURE); 
                } 
                steps[chn] = areas[chn].step / 8; 
                samples[chn] += offset * steps[chn]; 
        } 
        /* fill the channel areas */ 
        while (count-- > 0) { 
                res = sin(phase) *sin(phase) * maxval; 
                ires = res; 
                tmp = (unsigned char *)(&ires); 
                for (chn = 0; chn < channels; chn++) { 
                        for (byte = 0; byte < (unsigned int)bps; byte++) 
                                *(samples[chn] + byte) = tmp[byte]; 
                        samples[chn] += steps[chn]; 
                } 
                phase += step; 
                if (phase >= max_phase) 
                        phase -= max_phase; 
        } 
        *_phase = phase; 
} 
 
static int set_hwparams(snd_pcm_t *handle, 
                        snd_pcm_hw_params_t *params, 
                        snd_pcm_access_t access) 
{ 
        unsigned int rrate; 
        snd_pcm_uframes_t size; 
        int err, dir; 
 
        /* choose all parameters */ 
        snd_pcm_hw_params_any(handle, params); 
        /* set hardware resampling */ 
        snd_pcm_hw_params_set_rate_resample(handle, params, resample); 
        /* set the interleaved read/write format */ 
        err = snd_pcm_hw_params_set_access(handle, params, access); 
        /* set the sample format */ 
        err = snd_pcm_hw_params_set_format(handle, params, format); 
        /* set the count of channels */ 
        err = snd_pcm_hw_params_set_channels(handle, params, channels); 
        /* set the stream rate */ 
        rrate = rate; 
        err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); 
        if (err < 0) { 
                printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); 
                return err; 
        } 
        if (rrate != rate) { 
                printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); 
                return -EINVAL; 
        } 
        /* set the buffer time */ 
        snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir); 
        snd_pcm_hw_params_get_buffer_size(params, &size); 
        
        buffer_size = size; 
        /* set the period time */ 
        err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir); 
        if (err < 0) { 
                printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)); 
                return err; 
        } 
        err = snd_pcm_hw_params_get_period_size(params, &size, &dir); 
        if (err < 0) { 
                printf("Unable to get period size for playback: %s\n", snd_strerror(err)); 
                return err; 
        } 
        period_size = size; 
        /* write the parameters to device */ 
        err = snd_pcm_hw_params(handle, params); 
        if (err < 0) { 
                printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); 
                return err; 
        } 
        return 0; 
} 
 
static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams) 
{ 
        /* get the current swparams */ 
        snd_pcm_sw_params_current(handle, swparams); 
        /* start the transfer when the buffer is almost full: */ 
        /* (buffer_size / avail_min) * avail_min */ 
        snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size); 
        /* allow the transfer when at least period_size samples can be processed */ 
        snd_pcm_sw_params_set_avail_min(handle, swparams, period_size); 
        /* write the parameters to the playback device */ 
        snd_pcm_sw_params(handle, swparams); 
        return 0; 
} 
 
/* 
 *   Underrun and suspend recovery 
 */ 
  
static int xrun_recovery(snd_pcm_t *handle, int err) 
{ 
        if (err == -EPIPE) {    /* under-run */ 
                err = snd_pcm_prepare(handle); 
                if (err < 0) 
                        printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err)); 
                return 0; 
        } else if (err == -ESTRPIPE) { 
                while ((err = snd_pcm_resume(handle)) == -EAGAIN) 
                        sleep(1);       /* wait until the suspend flag is released */ 
                if (err < 0) { 
                        err = snd_pcm_prepare(handle); 
                        if (err < 0) 
                                printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err)); 
                } 
                return 0; 
        } 
        return err; 
} 
 
/* 
 *   Transfer method - write only 
 */ 
 
static int write_loop(snd_pcm_t *handle, 
                      signed short *samples, 
                      snd_pcm_channel_area_t *areas) 
{ 
        double phase = 0; 
        signed short *ptr; 
        int err, cptr; 
 
        while (1) { 
                generate_sine(areas, 0, period_size, &phase); 
                ptr = samples; 
                cptr = period_size; 
                while (cptr > 0) { 
                        err = snd_pcm_writei(handle, ptr, cptr); 
                        if (err == -EAGAIN) 
                                continue; 
                        if (err < 0) { 
                                if (xrun_recovery(handle, err) < 0) { 
                                        printf("Write error: %s\n", snd_strerror(err)); 
                                        exit(EXIT_FAILURE); 
                                } 
                                break;  /* skip one period */ 
                        } 
                        ptr += err * channels; 
                        cptr -= err; 
                } 
        } 
} 
  
int main(int argc, char *argv[]) 
{ 
	srand(time(NULL));
        snd_pcm_t *handle; 
        snd_pcm_hw_params_t *hwparams; 
        snd_pcm_sw_params_t *swparams; 
        signed short *samples; 
        unsigned int chn; 
        snd_pcm_channel_area_t *areas; 
 
        snd_pcm_hw_params_alloca(&hwparams); 
        snd_pcm_sw_params_alloca(&swparams); 
 
 
        if ( snd_output_stdio_attach(&output, stdout, 0)){ 
                printf("Output failed: %s\n", snd_strerror(0)); 
                return 0; 
        } 
 
        printf("Playback device is %s\n", device); 
        printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels); 
        printf("Sine wave rate is %.4fHz\n", freq); 
       
        snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0);
        set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
        set_swparams(handle, swparams);
        
        if (verbose > 0) 
                snd_pcm_dump(handle, output); 
 
        samples = malloc((period_size * channels * snd_pcm_format_width(format)) / 8); 
        if (samples == NULL) { 
                printf("No enough memory\n"); 
                exit(EXIT_FAILURE); 
        } 
         
        areas = calloc(channels, sizeof(snd_pcm_channel_area_t)); 
        if (areas == NULL) { 
                printf("No enough memory\n"); 
                exit(EXIT_FAILURE); 
        } 
        for (chn = 0; chn < channels; chn++) { 
                areas[chn].addr = samples; 
                areas[chn].first = chn * snd_pcm_format_width(format); 
                areas[chn].step = channels * snd_pcm_format_width(format); 
        } 
 
        write_loop(handle, samples, areas); 
   
 
        free(areas); 
        free(samples); 
        snd_pcm_close(handle); 
        return 0; 
}


Антидот

"Музиката, която не изобразява нищо е само шум."

Даламбер