Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1584624
  • 博文数量: 239
  • 博客积分: 1760
  • 博客等级: 上尉
  • 技术积分: 1595
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-08 23:53
文章分类

全部博文(239)

文章存档

2016年(1)

2015年(28)

2014年(53)

2013年(42)

2012年(50)

2011年(65)

分类: 嵌入式

2013-09-05 09:16:48

本设计思路:先打开一个普通wav音频文件,从定义的文件头前面的44个字节中,取出文件头的定义消息,置于一个文件头的结构体中。然后打开alsa音频驱动,从文件头结构体取出采样精度,声道数,采样频率三个重要参数,利用alsa音频驱动的API设置好参数,最后打开wav文件,定位到数据区,把音频数据依次写到音频驱动中去,开始播放,当写入完成后,退出写入的循环。

 

注意:本设计需要alsa的libasound-dev的库,编译链接时需要连接 —lasound. 

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include <string.h>
  4. #include <alsa/asoundlib.h>

  5. struct WAV_HEADER
  6. {
  7.     char rld[4]; //riff 标志符号
  8.     int rLen;
  9.     char wld[4]; //格式类型(wave)
  10.     char fld[4]; //"fmt"

  11.     int fLen; //sizeof(wave format matex)
  12.     
  13.     short wFormatTag; //编码格式
  14.     short wChannels; //声道数
  15.     int nSamplesPersec ; //采样频率
  16.     int nAvgBitsPerSample;//WAVE文件采样大小
  17.     short wBlockAlign; //块对齐
  18.     short wBitsPerSample; //WAVE文件采样大小
  19.     
  20.     char dld[4]; //”data“
  21.     int wSampleLength; //音频数据的大小

  22. } wav_header;

  23. int set_pcm_play(FILE *fp);

  24. int main(int argc,char *argv[])
  25. {

  26.     if(argc!=2)
  27.     {
  28.         printf("Usage:wav-player+wav file name\n");
  29.         exit(1);
  30.     }

  31.     int nread;
  32.     FILE *fp;
  33.     fp=fopen(argv[1],"rb");
  34.     if(fp==NULL)
  35.     {
  36.         perror("open file failed:\n");
  37.         exit(1);
  38.     }
  39.     
  40.     nread=fread(&wav_header,1,sizeof(wav_header),fp);
  41.     printf("nread=%d\n",nread);
  42.     
  43.     //printf("RIFF 标志%s\n",wav_header.rld);
  44.     printf("文件大小rLen:%d\n",wav_header.rLen);
  45.     //printf("wld=%s\n",wav_header.wld);
  46.     //printf("fld=%s\n",wav_header.fld);
  47.     
  48.    // printf("fLen=%d\n",wav_header.fLen);
  49.     
  50.     //printf("wFormatTag=%d\n",wav_header.wFormatTag);
  51.     printf("声道数:%d\n",wav_header.wChannels);
  52.     printf("采样频率:%d\n",wav_header.nSamplesPersec);
  53.     //printf("nAvgBitsPerSample=%d\n",wav_header.nAvgBitsPerSample);
  54.     //printf("wBlockAlign=%d\n",wav_header.wBlockAlign);
  55.     printf("采样的位数:%d\n",wav_header.wBitsPerSample);
  56.     
  57.    // printf("data=%s\n",wav_header.dld);
  58.     printf("wSampleLength=%d\n",wav_header.wSampleLength);
  59.     
  60.     
  61.     
  62.     
  63.     
  64.     set_pcm_play(fp);
  65.     return 0;
  66. }

  67. int set_pcm_play(FILE *fp)
  68. {
  69.         int rc;
  70.         int ret;
  71.         int size;
  72.         snd_pcm_t* handle; //PCI设备句柄
  73.         snd_pcm_hw_params_t* params;//硬件信息和PCM流配置
  74.         unsigned int val;
  75.         int dir=0;
  76.         snd_pcm_uframes_t frames;
  77.         char *buffer;
  78.         int channels=wav_header.wChannels;
  79.         int frequency=wav_header.nSamplesPersec;
  80.         int bit=wav_header.wBitsPerSample;
  81.         int datablock=wav_header.wBlockAlign;
  82.         unsigned char ch[100]; //用来存储wav文件的头信息
  83.     
  84.     
  85.         
  86.         rc=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
  87.         if(rc<0)
  88.         {
  89.                 perror("\nopen PCM device failed:");
  90.                 exit(1);
  91.         }


  92.         snd_pcm_hw_params_alloca(&params); //分配params结构体
  93.         if(rc<0)
  94.         {
  95.                 perror("\nsnd_pcm_hw_params_alloca:");
  96.                 exit(1);
  97.         }
  98.          rc=snd_pcm_hw_params_any(handle, params);//初始化params
  99.         if(rc<0)
  100.         {
  101.                 perror("\nsnd_pcm_hw_params_any:");
  102.                 exit(1);
  103.         }
  104.         rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); //初始化访问权限
  105.         if(rc<0)
  106.         {
  107.                 perror("\nsed_pcm_hw_set_access:");
  108.                 exit(1);

  109.         }

  110.         //采样位数
  111.         switch(bit/8)
  112.         {
  113.         case 1:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);
  114.                 break ;
  115.         case 2:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
  116.                 break ;
  117.         case 3:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24_LE);
  118.                 break ;

  119.         }
  120.         rc=snd_pcm_hw_params_set_channels(handle, params, channels); //设置声道,1表示单声>道,2表示立体声
  121.         if(rc<0)
  122.         {
  123.                 perror("\nsnd_pcm_hw_params_set_channels:");
  124.                 exit(1);
  125.         }
  126.         val = frequency;
  127.         rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); //设置>频率
  128.         if(rc<0)
  129.         {
  130.                 perror("\nsnd_pcm_hw_params_set_rate_near:");
  131.                 exit(1);
  132.         }

  133.         rc = snd_pcm_hw_params(handle, params);
  134.         if(rc<0)
  135.         {
  136.         perror("\nsnd_pcm_hw_params: ");
  137.         exit(1);
  138.         }

  139.         rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir); /*获取周期
  140. 长度*/
  141.         if(rc<0)
  142.         {
  143.                 perror("\nsnd_pcm_hw_params_get_period_size:");
  144.                 exit(1);
  145.         }

  146.         size = frames * datablock; /*4 代表数据快长度*/

  147.         buffer =(char*)malloc(size);
  148.     fseek(fp,58,SEEK_SET); //定位歌曲到数据区

  149.     while (1)
  150.         {
  151.                 memset(buffer,0,sizeof(buffer));
  152.                 ret = fread(buffer, 1, size, fp);
  153.                 if(ret == 0)
  154.                 {
  155.                         printf("歌曲写入结束\n");
  156.                         break;
  157.                 }
  158.                  else if (ret != size)
  159.                 {
  160.                  }
  161.                 // 写音频数据到PCM设备
  162.         while(ret = snd_pcm_writei(handle, buffer, frames)<0)
  163.            {
  164.                  usleep(2000);
  165.                  if (ret == -EPIPE)
  166.                 {
  167.                   /* EPIPE means underrun */
  168.                   fprintf(stderr, "underrun occurred\n");
  169.                   //完成硬件参数设置,使设备准备好
  170.                   snd_pcm_prepare(handle);
  171.                  }
  172.                  else if (ret < 0)
  173.                  {
  174.                           fprintf(stderr,
  175.                       "error from writei: %s\n",
  176.                       snd_strerror(ret));
  177.                  }
  178.             }

  179.     }

  180.         snd_pcm_drain(handle);
  181.         snd_pcm_close(handle);
  182.         free(buffer);
  183.         return 0;
  184. }

阅读(1607) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~