程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> libsndfile 用法簡介

libsndfile 用法簡介

編輯:C++入門知識

最近要做些聲學信號檢測方面的工作。需要對一些 wav 格式的文件進行分析處理。google 了一番,發現了 libsndfile。libsndfile 是一個 C 語言寫成的 開放源代碼的音頻文件讀寫的庫。可以讀寫 WAV 格式,FLAC 格式和其他許多常見格式(因為專利原因不支持MP3)。LGPL 協議。

libsndfile 的用法很簡單。


[cpp]
SNDFILE* sf_open(const char *path, int mode, SF_INFO *sfinfo); 

SNDFILE* sf_open(const char *path, int mode, SF_INFO *sfinfo);用來打開一個音頻文件。 mode 有三個選項。
SFM_READ    - read only mode
SFM_WRITE   - write only mode
SFM_RDWR    - read/write mode

音頻文件的一些基本信息由 sfinfo 來返回。


[cpp]
typedef struct 
{   sf_count_t  frames ;     /* Used to be called samples. */ 
    int         samplerate ; 
    int         channels ; 
    int         format ; 
    int         sections ; 
    int         seekable ; 
} SF_INFO ; 

typedef struct
{   sf_count_t  frames ;     /* Used to be called samples. */
    int         samplerate ;
    int         channels ;
    int         format ;
    int         sections ;
    int         seekable ;
} SF_INFO ;需要注意的是,如果是SFM_READ 模式打開一個文件, sfinfo 的 format 字段應預先寫為 0 。
打開音頻文件後,測試 format 的各個字段就能知道音頻文件的基本類型。
[cpp]
sf_count_t sf_seek(SNDFILE *sndfile, sf_count_t frames, int whence); 

sf_count_t sf_seek(SNDFILE *sndfile, sf_count_t frames, int whence);用來在音頻文件的數據區中移動文件指針,有點像 lseek 函數。不過sf_seek 函數自動的屏蔽了非數據區的部分。所有的移動都是在數據區中進行了,而且是以數據幀為單位,相當的方便。


[cpp]
sf_count_t  sf_read_short   (SNDFILE *sndfile, short *ptr, sf_count_t items) ; 
sf_count_t  sf_read_int     (SNDFILE *sndfile, int *ptr, sf_count_t items) ; 
sf_count_t  sf_read_float   (SNDFILE *sndfile, float *ptr, sf_count_t items) ; 
sf_count_t  sf_read_double  (SNDFILE *sndfile, double *ptr, sf_count_t items) ; 
sf_count_t  sf_readf_short   (SNDFILE *sndfile, short *ptr, sf_count_t frames) ; 
sf_count_t  sf_readf_int     (SNDFILE *sndfile, int *ptr, sf_count_t frames) ; 
sf_count_t  sf_readf_float   (SNDFILE *sndfile, float *ptr, sf_count_t frames) ; 
sf_count_t  sf_readf_double  (SNDFILE *sndfile, double *ptr, sf_count_t frames) ; 

sf_count_t  sf_read_short   (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
sf_count_t  sf_read_int     (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
sf_count_t  sf_read_float   (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
sf_count_t  sf_read_double  (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
sf_count_t  sf_readf_short   (SNDFILE *sndfile, short *ptr, sf_count_t frames) ;
sf_count_t  sf_readf_int     (SNDFILE *sndfile, int *ptr, sf_count_t frames) ;
sf_count_t  sf_readf_float   (SNDFILE *sndfile, float *ptr, sf_count_t frames) ;
sf_count_t  sf_readf_double  (SNDFILE *sndfile, double *ptr, sf_count_t frames) ;
上面 8 個函數用來從音頻文件中讀取數據。 這裡來說一說 items 和 frames 的區別。
對於單聲道的音頻文件。 item 和 frame 是一樣的。 一個 item 對應一個數據點。
對於多聲道音頻文件,一個 frame 包含多個數據點,比如雙聲道音頻文件,一個 frame 包括 2 個 item。
另外,音頻文件中可能用 8 bits 來存儲一個數據點,也可能是 16bits,可能用整數也可能用浮點數來存儲音頻數據。sf_read_XXX 系列函數會替你完成數據的轉換工作。
下面是一個簡單的例子,讀取一個音頻文件,顯示其基本信息,並將數據存儲到文本文件中。 這裡假設音頻文件為單聲道。
[cpp]
#include    <stdio.h>  
#include    <stdlib.h>  
#include    <sndfile.h>  
 
void save(short *b1, double *b2, int n); 
int main(int argc, char * argv[]) 

    SF_INFO sf_info; 
    SNDFILE *snd_file; 
    short *buf1; 
    double *buf2; 
    if(argc != 2) 
    { 
        exit(1); 
    } 
    sf_info.format = 0; 
    snd_file = sf_open(argv[1], SFM_READ, &sf_info) ; 
    printf ("Using %s.\n", sf_version_string ()) ; 
    printf("File Name : %s\n", argv[1]); 
    printf("Sample Rate : %d\n", sf_info.samplerate); 
    printf("Channels : %d\n", sf_info.channels); 
    printf("Sections  : %d\n", sf_info.sections ); 
    printf("Frames   : %d\n", (int)sf_info.frames  ); 
 
    buf1 = (short *)malloc(sf_info.frames *sizeof(short)); 
    buf2 = (double *)malloc(sf_info.frames *sizeof(double)); 
    sf_readf_short(snd_file, buf1, sf_info.frames) ; 
    sf_seek  (snd_file, 0, SEEK_SET) ; 
    sf_readf_double(snd_file, buf2, sf_info.frames) ; 
    save(buf1, buf2, sf_info.frames); 
    free(buf1); 
    free(buf2); 
    sf_close(snd_file); 
    return 0; 

 
void save(short *b1, double *b2, int n) 

    int i; 
    FILE *fp1; 
    FILE *fp2; 
    fp1 = fopen("short.dat", "w"); 
    fp2 = fopen("double.dat", "w"); 
    for(i = 0; i< n; i++) 
    { 
            fprintf(fp1, "%d\n", (int)b1[i]); 
            fprintf(fp2, "%f\n", b2[i]); 
    } 
    fclose(fp1); 
    fclose(fp2); 

#include <stdio.h>
#include <stdlib.h>
#include <sndfile.h>

void save(short *b1, double *b2, int n);
int main(int argc, char * argv[])
{
    SF_INFO sf_info;
    SNDFILE *snd_file;
    short *buf1;
    double *buf2;
    if(argc != 2)
    {
        exit(1);
    }
    sf_info.format = 0;
    snd_file = sf_open(argv[1], SFM_READ, &sf_info) ;
    printf ("Using %s.\n", sf_version_string ()) ;
    printf("File Name : %s\n", argv[1]);
    printf("Sample Rate : %d\n", sf_info.samplerate);
    printf("Channels : %d\n", sf_info.channels);
    printf("Sections  : %d\n", sf_info.sections );
    printf("Frames   : %d\n", (int)sf_info.frames  );

    buf1 = (short *)malloc(sf_info.frames *sizeof(short));
    buf2 = (double *)malloc(sf_info.frames *sizeof(double));
    sf_readf_short(snd_file, buf1, sf_info.frames) ;
    sf_seek  (snd_file, 0, SEEK_SET) ;
    sf_readf_double(snd_file, buf2, sf_info.frames) ;
    save(buf1, buf2, sf_info.frames);
    free(buf1);
    free(buf2);
    sf_close(snd_file);
    return 0;
}

void save(short *b1, double *b2, int n)
{
    int i;
    FILE *fp1;
    FILE *fp2;
    fp1 = fopen("short.dat", "w");
    fp2 = fopen("double.dat", "w");
    for(i = 0; i< n; i++)
    {
            fprintf(fp1, "%d\n", (int)b1[i]);
            fprintf(fp2, "%f\n", b2[i]);
    }
    fclose(fp1);
    fclose(fp2);
}
編譯命令如下:
mingw32-gcc.exe -Wall  -g  -IC:\MinGW\msys\1.0\local\include  C:\MinGW\msys\1.0\home\Administrator\wav_test\main.c -o bin\Debug\wav_test.exe    C:\MinGW\msys\1.0\local\lib\libsndfile.dll.a


與之相對應的是寫音頻文件。


[cpp]
sf_count_t  sf_write_short   (SNDFILE *sndfile, short *ptr, sf_count_t items) ; 
sf_count_t  sf_write_int     (SNDFILE *sndfile, int *ptr, sf_count_t items) ; 
sf_count_t  sf_write_float   (SNDFILE *sndfile, float *ptr, sf_count_t items) ; 
sf_count_t  sf_write_double  (SNDFILE *sndfile, double *ptr, sf_count_t items) ; 
sf_count_t  sf_writef_short  (SNDFILE *sndfile, short *ptr, sf_count_t frames) ; 
sf_count_t  sf_writef_int    (SNDFILE *sndfile, int *ptr, sf_count_t frames) ; 
sf_count_t  sf_writef_float  (SNDFILE *sndfile, float *ptr, sf_count_t frames) ; 
sf_count_t  sf_writef_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ; 

sf_count_t  sf_write_short   (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
sf_count_t  sf_write_int     (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
sf_count_t  sf_write_float   (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
sf_count_t  sf_write_double  (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
sf_count_t  sf_writef_short  (SNDFILE *sndfile, short *ptr, sf_count_t frames) ;
sf_count_t  sf_writef_int    (SNDFILE *sndfile, int *ptr, sf_count_t frames) ;
sf_count_t  sf_writef_float  (SNDFILE *sndfile, float *ptr, sf_count_t frames) ;
sf_count_t  sf_writef_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ;下面再給一個寫音頻文件的例子:


[cpp]
#include    <stdio.h>  
#include    <stdlib.h>  
#include    <string.h>  
#include    <math.h>  
#include    <sndfile.h>  
 
#define     SAMPLE_RATE         44100  
#define     SAMPLE_COUNT        (SAMPLE_RATE * 4)   /* 4 seconds */  
#define     AMPLITUDE           (1.0 * 0x7F000000)  
#define     LEFT_FREQ           (344.0 / SAMPLE_RATE)  
#define     RIGHT_FREQ          (2 * 344.0 / SAMPLE_RATE)  
 
int main (void) 
{   SNDFILE *file ; 
    SF_INFO sfinfo ; 
    int     k ; 
    int *buffer ; 
 
    if (! (buffer = malloc (2 * SAMPLE_COUNT * sizeof (int)))) 
    {   printf ("Malloc failed.\n") ; 
        exit (0) ; 
    } ; 
 
    memset (&sfinfo, 0, sizeof (sfinfo)) ; 
 
    sfinfo.samplerate   = SAMPLE_RATE ; 
    sfinfo.frames       = SAMPLE_COUNT ; 
    sfinfo.channels     = 2 ; 
    sfinfo.format       = (SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; 
 
    if (! (file = sf_open ("sine.wav", SFM_WRITE, &sfinfo))) 
    {   printf ("Error : Not able to open output file.\n") ; 
        return 1 ; 
    } ; 
 
 
    for (k = 0 ; k < SAMPLE_COUNT ; k++) 
    {   buffer [2 * k] = AMPLITUDE * sin (LEFT_FREQ * 2 * k * M_PI) ; 
        buffer [2 * k + 1] = AMPLITUDE * cos (RIGHT_FREQ * 2 * k * M_PI) ; 
    } ; 
 
    if (sf_write_int (file, buffer, sfinfo.channels * SAMPLE_COUNT) != sfinfo.channels * SAMPLE_COUNT) 
        puts (sf_strerror (file)) ; 
 
    sf_close (file) ; 
    return   0 ; 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sndfile.h>

#define  SAMPLE_RATE   44100
#define  SAMPLE_COUNT  (SAMPLE_RATE * 4) /* 4 seconds */
#define  AMPLITUDE   (1.0 * 0x7F000000)
#define  LEFT_FREQ   (344.0 / SAMPLE_RATE)
#define  RIGHT_FREQ   (2 * 344.0 / SAMPLE_RATE)

int main (void)
{ SNDFILE *file ;
 SF_INFO sfinfo ;
 int  k ;
 int *buffer ;

 if (! (buffer = malloc (2 * SAMPLE_COUNT * sizeof (int))))
 { printf ("Malloc failed.\n") ;
  exit (0) ;
 } ;

 memset (&sfinfo, 0, sizeof (sfinfo)) ;

 sfinfo.samplerate = SAMPLE_RATE ;
 sfinfo.frames  = SAMPLE_COUNT ;
 sfinfo.channels  = 2 ;
 sfinfo.format  = (SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;

 if (! (file = sf_open ("sine.wav", SFM_WRITE, &sfinfo)))
 { printf ("Error : Not able to open output file.\n") ;
  return 1 ;
 } ;


 for (k = 0 ; k < SAMPLE_COUNT ; k++)
 { buffer [2 * k] = AMPLITUDE * sin (LEFT_FREQ * 2 * k * M_PI) ;
  buffer [2 * k + 1] = AMPLITUDE * cos (RIGHT_FREQ * 2 * k * M_PI) ;
 } ;

 if (sf_write_int (file, buffer, sfinfo.channels * SAMPLE_COUNT) != sfinfo.channels * SAMPLE_COUNT)
  puts (sf_strerror (file)) ;

 sf_close (file) ;
 return  0 ;
}
除此之外,還有些其他的函數。用法都比較簡單,這裡就不多介紹了。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved