alsa编程之播放"嘀嘀"音

本文详细介绍了如何使用ARM Linux GCC交叉编译器编写、编译和运行C语言代码,实现通过缓冲区直接写入PCM数据进行连续播放音效的功能。通过设置硬件参数和调用snd_pcm_writei函数,实现在A8板子上模拟万用表表针短接的‘滴滴’音效果。

    项目要求A8板子能够不间断的发出"嘀嘀"音,类似于万用表表针短接的情形。这样的话可以有两种方案:(1)录制一个较长时间的"嘀嘀"音音频文件,用mplayer播放;(2)用户空间编程直接向缓冲写入一3K Hz左右的的PCM数据,循环播放。在这里采用方案(2).下面是代码。

#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>

#define BUFF_SIZE 2048

int main (int argc, char *argv[])
{
  int err;
  short buff[BUFF_SIZE];
  int rate = 44100; /* Sample rate */
  unsigned int exact_rate; /* Sample rate returned by */
  /* Handle for the PCM device */
  snd_pcm_t *playback_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 *hw_params;

  int j;   //用44.1KHz一个周期采样16个点,得到的频率大概在2.75K,一个正玄波采样16个点也方便计算,峰值32000,这样得到的16个数据如下
  for(j=0;j<128;j++)
	{
		buff[j*16]=0;
		buff[j*16+1]=12245;
		buff[j*16+2]=22627;
		buff[j*16+3]=29563;
		buff[j*16+4]=32000;
		buff[j*16+5]=29563;
		buff[j*16+6]=22627;
		buff[j*16+7]=12245;
		buff[j*16+8]=0;
		buff[j*16+9]=-12245;
		buff[j*16+10]=-22627;
		buff[j*16+11]=-29563;
		buff[j*16+12]=-32000;
		buff[j*16+13]=-29563;
		buff[j*16+14]=-22627;
		buff[j*16+15]=-12245;
	}

  /* 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. */

  static char *device = "default"; /* playback device */

  /* Open PCM. The last parameter of this function is the mode. */
  if ((err = snd_pcm_open (&playback_handle, device, stream, 0)) < 0) {
    fprintf (stderr, "cannot open audio device (%s)\n", snd_strerror (err));
    exit (1);
  }

  /* Allocate the snd_pcm_hw_params_t structure on the stack. */
  if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
    fprintf (stderr, "cannot allocate hardware parameters (%s)\n", snd_strerror (err));
    exit (1);
  }


  /* Init hwparams with full configuration space */
  if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) {
    fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err));
    exit (1);
  }

    /* Set access type. */
    if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
      fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err));
      exit (1);
    }

    /* Set sample format */
    if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
      fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err));
      exit (1);
    }

    /* Set sample rate. If the exact rate is not supported by the hardware, use nearest possible rate. */
    exact_rate = rate;
    if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, &exact_rate, 0)) < 0) {
      fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err));
      exit (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 ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0) {
      fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err));
      exit (1);
    }


    /* Apply HW parameter settings to PCM device and prepare device. */
     if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) {
       fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err));
       exit (1);
     }

     snd_pcm_hw_params_free (hw_params);

     if ((err = snd_pcm_prepare (playback_handle)) < 0) {
       fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err));
       exit (1);
     }

    int i;
    for(i=0;i<300;i++)
     if ((err = snd_pcm_writei (playback_handle, buff, BUFF_SIZE/2)) != BUFF_SIZE/2) {
       fprintf (stderr, "write to audio interface failed (%s)\n", snd_strerror (err));
       exit (1);
     }


     snd_pcm_close (playback_handle);

     exit (0);
}



用4.5.1的交叉编译器编译:arm-linux-gcc  -o playDD playDD.c -lasound,拷到板子上运行。

需要注意的一点是 函数snd_pcm_writei的第三个参数是要写入数据帧的大小,在立体声双通道的情况下,这里函数参数值应该为写入缓冲长度值除以2。函数说明如下:

snd_pcm_writei()
snd_pcm_sframes_t snd_pcm_writei (snd_pcm_t * pcm,
                                             const void * buffer,
                                                  snd_pcm_uframes_t size
                                                   )
Write interleaved frames to a PCM.
Parameters:
      	pcm  	PCM handle
      	buffer  frames containing buffer
      	size  	frames to be written 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值