linux 音頻編程

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

 

一、音頻開發模型:編程

OSS(open sound system)  linux/unix 平臺的上早期的統一音頻接口。linux kernl 2.6 版本之前其它提供兩種設備文件以供編程。 經常使用的操做函數爲open、close、read、write、ioctl.ubuntu

(/dev/dsp錄音設備文件/dev/audio播放設備文件)windows

ALSA(a)目前流行的編譯框架。linux 2.6 版本發後支持。bash

提供統一的編程接口:snd_pcm_open、snd_pcm_close、snd_pcm_hw_params框架

基設備文件爲:/dev/snd/pcmC0D0p    /dev/snd/pcmC0D0c  /dev/snd/pcmC0D1p   /dev/snd/timer函數

能夠經過bash命令查看 alsa 驅動版本:oop

root@ubuntu:cat  /proc/asound/version編碼

Advanced linux Sound Architecture Driver Version 1.0.23spa

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\n",  
            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\n",  
            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\n");  
      snd_pcm_prepare(handle);  
    } else if (rc < 0) {  
      fprintf(stderr,  
              "error from read: %s\n",  
              snd_strerror(rc));  
    } else if (rc != (int)frames) {  
      fprintf(stderr, "short read, read %d frames\n", rc);  
    }  
  
    if(write(fd_f, buffer, size)==-1)  
    {  
         perror("write to sound wrong!!");  
    }  
    if (rc != size)  
      fprintf(stderr,  
              "short write: wrote %d bytes\n", 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;
}
相關文章
相關標籤/搜索