Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1158993
  • 博文数量: 221
  • 博客积分: 10152
  • 博客等级: 上将
  • 技术积分: 1518
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-22 10:42
文章分类

全部博文(221)

文章存档

2018年(1)

2015年(6)

2014年(3)

2013年(4)

2012年(1)

2011年(5)

2010年(14)

2009年(10)

2008年(28)

2007年(33)

2006年(114)

2005年(2)

我的朋友

分类: LINUX

2014-10-28 15:08:37

基于Linux ALSA音频驱动的wav文件解析及播放程序 2012-08-28 07:13:34

分类: 嵌入式

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

 

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

 

 

#include
#include
#include
#include

struct WAV_HEADER
{
    char rld[4];    //riff
标志符号
    int rLen;  
    char wld[4];    //
格式类型(wave
    char fld[4];    //"fmt"

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

} wav_header;

int set_pcm_play(FILE *fp);

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

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

    int nread;
    FILE *fp;
    fp=fopen(argv[1],"rb");
    if(fp==NULL)
    {
        perror("open file failed:\n");
        exit(1);
    }
   
    nread=fread(&wav_header,1,sizeof(wav_header),fp);
    printf("nread=%d\n",nread);
    
    //printf("RIFF
标志%s\n",wav_header.rld);
    printf("
文件大小rLen
%d\n",wav_header.rLen);
    //printf("wld=%s\n",wav_header.wld);
    //printf("fld=%s\n",wav_header.fld);
   
   // printf("fLen=%d\n",wav_header.fLen);
   
    //printf("wFormatTag=%d\n",wav_header.wFormatTag);
    printf("
声道数:
%d\n",wav_header.wChannels);
    printf("
采样频率:
%d\n",wav_header.nSamplesPersec);
    //printf("nAvgBitsPerSample=%d\n",wav_header.nAvgBitsPerSample);
    //printf("wBlockAlign=%d\n",wav_header.wBlockAlign);
    printf("
采样的位数:
%d\n",wav_header.wBitsPerSample);
   
   // printf("data=%s\n",wav_header.dld);
    printf("wSampleLength=%d\n",wav_header.wSampleLength);
   
   
   
   
   
    set_pcm_play(fp);
    return 0;
}

int set_pcm_play(FILE *fp)
{
        int    rc;
        int    ret;
        int    size;
        snd_pcm_t*       handle;        //PCI
设备句柄

        snd_pcm_hw_params_t*      params;//
硬件信息和PCM流配置
        unsigned int       val;
        int                dir=0;
        snd_pcm_uframes_t  frames;
        char   *buffer;
        int channels=wav_header.wChannels;
        int frequency=wav_header.nSamplesPersec;
        int bit=wav_header.wBitsPerSample;
        int datablock=wav_header.wBlockAlign;
        unsigned char ch[100];  //
用来存储wav文件的头信息
   
   
       
        rc=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
        if(rc<0)
        {
                perror("\nopen PCM device failed:");
                exit(1);
        }


        snd_pcm_hw_params_alloca(¶ms); //
分配params结构体
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_alloca:");
                exit(1);
        }
         rc=snd_pcm_hw_params_any(handle, params);//
初始化params
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_any:");
                exit(1);
        }
        rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);                                 //
初始化访问权限

        if(rc<0)
        {
                perror("\nsed_pcm_hw_set_access:");
                exit(1);

        }

        //
采样位数
        switch(bit/8)
        {
        case 1:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);
                break ;
        case 2:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
                break ;
        case 3:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24_LE);
                break ;

        }
        rc=snd_pcm_hw_params_set_channels(handle, params, channels);  //
设置声道,1表示单声>道,2表示立体声
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_set_channels:");
                exit(1);
        }
        val = frequency;
        rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);  //
设置>频率
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_set_rate_near:");
                exit(1);
        }

        rc = snd_pcm_hw_params(handle, params);
        if(rc<0)
        {
        perror("\nsnd_pcm_hw_params: ");
        exit(1);
        }

        rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir);  /*
获取周期
长度*/
        if(rc<0)
        {
                perror("\nsnd_pcm_hw_params_get_period_size:");
                exit(1);
        }

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

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


    while (1)
        {
                memset(buffer,0,sizeof(buffer));
                ret = fread(buffer, 1, size, fp);
                if(ret == 0)
                {
                        printf("
歌曲写入结束\n");
                        break;
                }
                 else if (ret != size)
                {
                 }
                //
写音频数据到PCM设备
 
        while(ret = snd_pcm_writei(handle, buffer, frames)<0)
           {
                 usleep(2000); 
                 if (ret == -EPIPE)
                {
                  /* EPIPE means underrun */
                  fprintf(stderr, "underrun occurred\n");
                  //
完成硬件参数设置,使设备准备好
 
                  snd_pcm_prepare(handle);
                 }
                 else if (ret < 0)
                 {
                          fprintf(stderr,
                      "error from writei: %s\n",
                      snd_strerror(ret));
                 }
            }

    }

        snd_pcm_drain(handle);
        snd_pcm_close(handle);
        free(buffer);
        return 0;
}
 

阅读(926) | 评论(0) | 转发(0) |
0

上一篇:WAV文件播放

下一篇:coredump 设置

给主人留下些什么吧!~~