zoukankan      html  css  js  c++  java
  • 基于Linux ALSA音频驱动的wav文件解析及播放程序 2012

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

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

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

    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 ");
            exit(1);
        }

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


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

            if(rc<0)
            {
                    perror(" sed_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(" snd_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(" snd_pcm_hw_params_set_rate_near:");
                    exit(1);
            }

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

            rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir);  /*
    获取周期
    长度*/
            if(rc<0)
            {
                    perror(" snd_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("
    歌曲写入结束 ");
                            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 ");
                      //完成硬件参数设置,使设备准备好
      
                      snd_pcm_prepare(handle);
                     }
                     else if (ret < 0)
                     {
                              fprintf(stderr,
                          "error from writei: %s ",
                          snd_strerror(ret));
                     }
                }

        }

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

    基于Linux ALSA音频驱动的wav文件解析及播放程序 作者:东方钰

  • 相关阅读:
    elasticsearch操作命令
    mysql-清除binlog日志命令
    TensorFlow 基础 (03)
    TensorFlow 基础 (02)
    TensorFlow 基础 (01)
    Python 基础练手 32 道
    Pandas 批量处理文本表
    Pandas 清除 Excel 特殊字符
    MNIST实例-Tensorflow 初体验
    字符串和文本 (02)
  • 原文地址:https://www.cnblogs.com/cainiaoaixuexi/p/3920424.html
Copyright © 2011-2022 走看看