libsndfile 用法简介

最近要做些声学信号检测方面的工作。需要对一些 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 ;
}

除此之外,还有些其他的函数。用法都比较简单,这里就不多介绍了。

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值