Упражнение 7. Аудио контролер

From Ilianko
Revision as of 18:58, 27 April 2011 by Anko (talk | contribs)

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

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

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

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

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

libasound2-dev

#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
	      
int main (int argc, char *argv[])
{
  /* Handle for the PCM device */ 
  snd_pcm_t *pcm_handle;          

  /* Playback stream */
  snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;

  /* This structure contains information about    */
  /* the hardware and can be used to specify the  */      
  /* configuration to be used for the PCM stream. */ 
  snd_pcm_hw_params_t *hwparams;


   /* Name of the PCM device, like plughw:0,0          */
    /* The first number is the number of the soundcard, */
    /* the second number is the number of the device.   */
    char *pcm_name;
  
  /* Init pcm_name. Of course, later you */
    /* will make this configurable ;-)     */
   pcm_name = strdup("default");
  
    /* Allocate the snd_pcm_hw_params_t structure on the stack. */
    snd_pcm_hw_params_alloca(&hwparams);
  
    /* Open PCM. The last parameter of this function is the mode. */
    /* If this is set to 0, the standard mode is used. Possible   */
    /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.       */ 
    /* If SND_PCM_NONBLOCK is used, read / write access to the    */
    /* PCM device will return immediately. If SND_PCM_ASYNC is    */
    /* specified, SIGIO will be emitted whenever a period has     */
    /* been completely processed by the soundcard.                */
    if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0) {
      fprintf(stderr, "Error opening PCM device %s\n", pcm_name);
      return(-1);
    }
    
    
    /* Init hwparams with full configuration space */
    if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
      fprintf(stderr, "Can not configure this PCM device.\n");
      return(-1);
    }
    
    
    
    
    
    unsigned int rate = 44100; /* Sample rate */
    unsigned int exact_rate;   /* Sample rate returned by */
                      /* snd_pcm_hw_params_set_rate_near */ 
    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;
        data[8*l2+5] = s3 >> 8;
        data[8*l2+6] = (unsigned char)s3;
        data[8*l2+7] = s4 >> 8;
      
      }
      while ((pcmreturn = snd_pcm_writei(pcm_handle, data, frames)) < 0) {
        snd_pcm_prepare(pcm_handle);
        fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
      }
    }
    /*
    
     unsigned char *data;
    int pcmreturn, l1, l2;
    short s1, s2;
    int frames;

    data = (unsigned char *)malloc(periodsize);
    frames = periodsize >> 2;
    for(l1 = 0; l1 < 10000; l1++) {
      for(l2 = 0; l2 < frames; l2++) {
        s1 = (l2 % 128) * 100 - 5000;  
        s2 = (l2 % 256) * 100 - 5000;  
        data[4*l2] = (unsigned char)s1;
        data[4*l2+1] = s1 >> 8;
        data[4*l2+2] = (unsigned char)s2;
        data[4*l2+3] = s2 >> 8;
      }
      while ((pcmreturn = snd_pcm_writei(pcm_handle, data, frames)) < 0) {
        snd_pcm_prepare(pcm_handle);
        fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
      }
    }*/
  return 0;
}


Антидот

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

Даламбер