zoukankan      html  css  js  c++  java
  • linux 音频编程

    http://blog.csdn.net/sea918/article/details/7249216

     

    1、音频开发模型:

    OSS(open sound system)  linux/unix 平台的上早期的统一音频接口。linux kernl 2.6 版本以前其它提供两种设备文件以供编程。 常用的操作函数为open、close、read、write、ioctl.

    (/dev/dsp录音设备文件/dev/audio播放设备文件)

    ALSA(a)目前流行的编译框架。linux 2.6 版本发后支持。

    提供统一的编程接口:snd_pcm_open、snd_pcm_close、snd_pcm_hw_params

    基设备文件为:/dev/snd/pcmC0D0p    /dev/snd/pcmC0D0c  /dev/snd/pcmC0D1p   /dev/snd/timer

    可以通过bash命令查看 alsa 驱动版本:

    root@ubuntu:cat  /proc/asound/version

    Advanced linux Sound Architecture Driver Version 1.0.23

    2,Alsa-lib 编译

    a,下载并安装 alsa-lib库

    root@ubuntu: tar -xvf  alsa-lib-1.0.13.tar.bz2

    root@ubuntu:./configure

    root@ubuntu:make

    root@ubuntu: make install

    3,编程

    a,添加头文件

    #include <alsa/asoundlib.h>

    b,编程录音代码.

    */  
      
    /* Use the newer ALSA API */  
    #define ALSA_PCM_NEW_HW_PARAMS_API  
    #include <stdio.h>  
    #include <stdlib.h>  
    #include <alsa/asoundlib.h>  
      
    #define LENGTH    3   //录音时间,秒  
    #define RATE    9600 //采样频率  
    #define SIZE    16   //量化位数  
    #define CHANNELS 1   //声道数目  
    #define RSIZE    8    //buf的大小,  
      
    /********以下是wave格式文件的文件头格式说明******/  
    /*------------------------------------------------ 
    |             RIFF WAVE Chunk                  | 
    |             ID = 'RIFF'                     | 
    |             RiffType = 'WAVE'                | 
    ------------------------------------------------ 
    |             Format Chunk                     | 
    |             ID = 'fmt '                      | 
    ------------------------------------------------ 
    |             Fact Chunk(optional)             | 
    |             ID = 'fact'                      | 
    ------------------------------------------------ 
    |             Data Chunk                       | 
    |             ID = 'data'                      | 
    ------------------------------------------------*/  
    /**********以上是wave文件格式头格式说明***********/  
    /*wave 文件一共有四个Chunk组成,其中第三个Chunk可以省略,每个Chunk有标示(ID), 
    大小(size,就是本Chunk的内容部分长度),内容三部分组成*/  
    struct fhead  
    {  
    /****RIFF WAVE CHUNK*/  
    unsigned char a[4];//四个字节存放'R','I','F','F'  
    long int b;        //整个文件的长度-8;每个Chunk的size字段,都是表示除了本Chunk的ID和SIZE字段外的长度;  
    unsigned char c[4];//四个字节存放'W','A','V','E'  
    /****RIFF WAVE CHUNK*/  
    /****Format CHUNK*/  
    unsigned char d[4];//四个字节存放'f','m','t',''  
    long int e;       //16后没有附加消息,18后有附加消息;一般为16,其他格式转来的话为18  
    short int f;       //编码方式,一般为0x0001;  
    short int g;       //声道数目,1单声道,2双声道;  
    long int h;        //采样频率;  
    long int i;        //每秒所需字节数;  
    short int j;       //每个采样需要多少字节,若声道是双,则两个一起考虑;  
    short int k;       //即量化位数  
    /****Format CHUNK*/  
    /***Data Chunk**/  
       unsigned char p[4];//四个字节存放'd','a','t','a'  
    long int q;        //语音数据部分长度,不包括文件头的任何部分  
    }wavehead;//定义WAVE文件的文件头结构体  
      
      
    int startRecord(void)  
    {  
    long loops;  
    int rc;  
    int size;  
    snd_pcm_t *handle;  
    snd_pcm_hw_params_t *params;  
    unsigned int val;  
    int dir;  
    snd_pcm_uframes_t frames;  
    char *buffer;  
    int fd_f;  
    int status;  
      
      
      
    /*以下wave 文件头赋值*/  
    wavehead.a[0]='R';  
    wavehead.a[1]='I';  
    wavehead.a[2]='F';  
    wavehead.a[3]='F';  
    wavehead.b=LENGTH*RATE*CHANNELS*SIZE/8-8;  
    wavehead.c[0]='W';  
    wavehead.c[1]='A';  
    wavehead.c[2]='V';  
    wavehead.c[3]='E';  
    wavehead.d[0]='f';  
    wavehead.d[1]='m';  
    wavehead.d[2]='t';  
    wavehead.d[3]=' ';  
    wavehead.e=16;  
    wavehead.f=1;  
    wavehead.g=CHANNELS;  
    wavehead.h=RATE;  
    wavehead.i=RATE*CHANNELS*SIZE/8;  
    wavehead.j=CHANNELS*SIZE/8;  
    wavehead.k=SIZE;  
    wavehead.p[0]='d';  
    wavehead.p[1]='a';  
    wavehead.p[2]='t';  
    wavehead.p[3]='a';  
    wavehead.q=LENGTH*RATE*CHANNELS*SIZE/8;  
    /*以上wave 文件头赋值*/  
      
      
    /* Open PCM device for recording (capture). */  
    rc = snd_pcm_open(&handle, "default",  
                        SND_PCM_STREAM_CAPTURE, 0);  
    if (rc < 0) {  
        fprintf(stderr,  
                "unable to open pcm device: %s
    ",  
                snd_strerror(rc));  
        exit(1);  
    }  
      
    /* Allocate a hardware parameters object. */  
    snd_pcm_hw_params_alloca(¶ms);  
      
    /* Fill it in with default values. */  
    snd_pcm_hw_params_any(handle, params);  
      
    /* Set the desired hardware parameters. */  
      
    /* Interleaved mode */  
    snd_pcm_hw_params_set_access(handle, params,  
                          SND_PCM_ACCESS_RW_INTERLEAVED);  
      
    /* Signed 16-bit little-endian format */  
    snd_pcm_hw_params_set_format(handle, params,  
                                  SND_PCM_FORMAT_S16_LE);  
      
    /* Two channels (stereo) */  
    snd_pcm_hw_params_set_channels(handle, params, CHANNELS);  
      
    /* 44100 bits/second sampling rate (CD quality) */  
    val = RATE;  
    snd_pcm_hw_params_set_rate_near(handle, params,  
                                      &val, &dir);  
      
    /* Set period size to 32 frames. */  
    frames = 32;  
    snd_pcm_hw_params_set_period_size_near(handle,  
                                  params, &frames, &dir);  
      
    /* Write the parameters to the driver */  
    rc = snd_pcm_hw_params(handle, params);  
    if (rc < 0) {  
        fprintf(stderr,  
                "unable to set hw parameters: %s
    ",  
                snd_strerror(rc));  
        exit(1);  
    }  
      
    /* Use a buffer large enough to hold one period */  
    snd_pcm_hw_params_get_period_size(params,  
                                          &frames, &dir);  
    size = frames * 2; /* 2 bytes/sample, 2 channels */  
    buffer = (char *) malloc(size);  
      
    /* We want to loop for 5 seconds */  
    snd_pcm_hw_params_get_period_time(params,  
                                             &val, &dir);  
    loops = 5000000 / val;  
      
      
      
      
    if(( fd_f = open("./sound.wav", O_CREAT|O_RDWR,0777))==-1)//创建一个wave格式语音文件  
    {  
        perror("cannot creat the sound file");  
    }  
    if((status = write(fd_f, &wavehead, sizeof(wavehead)))==-1)//写入wave文件的文件头  
    {  
       perror("write to sound'head wrong!!");  
    }  
      
    while (loops > 0) {  
        loops--;  
        rc = snd_pcm_readi(handle, buffer, frames);  
        if (rc == -EPIPE) {  
          /* EPIPE means overrun */  
          fprintf(stderr, "overrun occurred
    ");  
          snd_pcm_prepare(handle);  
        } else if (rc < 0) {  
          fprintf(stderr,  
                  "error from read: %s
    ",  
                  snd_strerror(rc));  
        } else if (rc != (int)frames) {  
          fprintf(stderr, "short read, read %d frames
    ", rc);  
        }  
      
        if(write(fd_f, buffer, size)==-1)  
        {  
             perror("write to sound wrong!!");  
        }  
        if (rc != size)  
          fprintf(stderr,  
                  "short write: wrote %d bytes
    ", rc);  
    }  
      
    snd_pcm_drain(handle);  
    snd_pcm_close(handle);  
    free(buffer);  
    close(fd_f);  
      
    return 0;  
    }

     

    OSS的编程

     

    Linux下和声卡相关的文件有许多,如采集数字样本的/dev/dsp文件,针对混音器的/dev/mixer文件以及用于音序器的/dev /sequencer等。文件/dev/audio是一个基于兼容性考虑的声音设备文件,它实际是到上述数字设备的一个映射,它最大的特色或许是对诸如 wav这类文件格式的直接支持。我们下面的例子即使用了此设备文件实现了一个简单的录音机:我们从声卡设备(当然要用麦克风)读取音频数据,并将它存放到 文件test.wav中去。要播放这个wav文件,只要如前面所述,使用命令cat test.wav >/dev/audio即可,当然你也可以用Linux下其他的多媒体软件来播放这个文件。

     

    /* 此文件中定义了下面所有形如SND_的变量*/
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <linux/soundcard.h>
     
    #define OPEN_DSP_FAILED     0x00000001      /*打开  dsp 失败!*/
    #define SAMPLERATE_STATUS     0x00000002    /*samplerate status failed*/
    #define SET_SAMPLERATE_FAILED  0x00000003   /*set samplerate failed*/
    #define CHANNELS_STATUS       0x00000004    /*Channels status failed*/
    #define SET_CHANNELS_FAILED    0x00000005   /*set channels failed*/
    #define FMT_STATUS       0x00000006        /*FMT status failed*/
    #define SET_FMT_FAILED     0x00000007       /*set fmt failed*/
    #define OPEN_FILE_FAILED        0x00000008    /*opem filed failed*/
     
    int P8100_Audio_Play(char *pathname,int nSampleRate,int nChannels,int fmt)
    {
    int dsp_fd,mix_fd,status,arg;
    dsp_fd = open("/dev/dsp" , O_RDWR);   /*open dsp*/
    if(dsp_fd < 0)
    {
      return  OPEN_DSP_FAILED;
    }
    arg = nSampleRate;
    status = ioctl(dsp_fd,SOUND_PCM_WRITE_RATE,&arg); /*set samplerate*/
    if(status < 0)
    {
      close(dsp_fd);
      return SAMPLERATE_STATUS;
    }
    if(arg != nSampleRate)
    {
      close(dsp_fd);
      return SET_SAMPLERATE_FAILED;
    }
    arg = nChannels;  /*set channels*/  
    status = ioctl(dsp_fd, SOUND_PCM_WRITE_CHANNELS, &arg);
    if(status < 0)
    {
      close(dsp_fd);
      return CHANNELS_STATUS;
    }
    if( arg != nChannels)
    {
      close(dsp_fd);
      return SET_CHANNELS_FAILED;
    }
    arg = fmt; /*set bit fmt*/
    status = ioctl(dsp_fd, SOUND_PCM_WRITE_BITS, &arg);
    if(status < 0)
    {
      close(dsp_fd);
      return FMT_STATUS;
    }
    if(arg != fmt)
    {
      close(dsp_fd);
      return SET_FMT_FAILED;
    }/*到此设置好了DSP的各个参数*/           
    FILE *file_fd = fopen(pathname,"r");
    if(file_fd == NULL)
    {
      close(dsp_fd);
      return OPEN_FILE_FAILED;
    }
    int num = 3*nChannels*nSampleRate*fmt/8;
    int get_num;
    char buf[num];
    while(feof(file_fd) == 0)
    {
      get_num = fread(buf,1,num,file_fd);
      write(dsp_fd,buf,get_num);
      if(get_num != num)
      {
       close(dsp_fd);
       fclose(file_fd);
       return 0;
      }
    }
    close(dsp_fd);
    fclose(file_fd);
    return 0;
    }
      
    int main()
    {
        int value;
     
        value = P8100_Audio_Play("/windows/C/WINDOWS/Media/Windows Startup.wav",44100,2,16);
        //注意播放文件的路径哦!!
        fprintf(stderr,"value is %d",value);
        return 0;
    }
  • 相关阅读:
    [cf1217F]Forced Online Queries Problem
    [cf1215F]Radio Stations
    超级楼梯[HDU2041]
    亲和数[HDU2040]
    三角形[HDU2039]
    今年暑假不AC[HDU2037]
    Counting Squares[HDU1264]
    CodeForces Round 195 Div2
    Square Coins[HDU1398]
    The number of divisors(约数) about Humble Numbers[HDU1492]
  • 原文地址:https://www.cnblogs.com/cute/p/5010035.html
Copyright © 2011-2022 走看看