项目要求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