最近要做些声学信号检测方面的工作。需要对一些 wav 格式的文件进行分析处理。google 了一番,发现了 libsndfile。libsndfile 是一个 C 语言写成的 开放源代码的音频文件读写的库。可以读写 WAV 格式,FLAC 格式和其他许多常见格式(因为专利原因不支持MP3)。LGPL 协议。
libsndfile 的用法很简单。
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 来返回。
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 的各个字段就能知道音频文件的基本类型。
sf_count_t sf_seek(SNDFILE *sndfile, sf_count_t frames, int whence);用来在音频文件的数据区中移动文件指针,有点像 lseek 函数。不过sf_seek 函数自动的屏蔽了非数据区的部分。所有的移动都是在数据区中进行了,而且是以数据帧为单位,相当的方便。
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 系列函数会替你完成数据的转换工作。
下面是一个简单的例子,读取一个音频文件,显示其基本信息,并将数据存储到文本文件中。 这里假设音频文件为单声道。
#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
与之相对应的是写音频文件。
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) ;下面再给一个写音频文件的例子:
#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 ; }
除此之外,还有些其他的函数。用法都比较简单,这里就不多介绍了。
作者:liyuanbhu 发表于2013-8-21 13:38:16 原文链接
阅读:41 评论:0 查看评论