音频编程 libsndfile

本文详细介绍如何使用libsndfile库生成指定频率的正弦波并保存为wav文件。通过具体代码示例,展示了从创建正弦信号到封装音频文件的全过程,包括参数设置、信号生成、数据处理和文件写入等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

音频编程 libsndfile

libsndfile是一个专门为读写音频采样文件(如wav或者AIFF)设计的C程序库。它支持多种格式,并且有简单易用的接口。在buildroot sdk中可以非常方便的配置和使用libsndfile。
下面的sample用来生成指定频率的正弦波并封装为wav文件。
正弦信号的规格是16k 采样率,1khz频率,-6db,S16_LE format,1 channel。

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

#include <sndfile.h>

#undef ARRAY_SIZE
#define ARRAY_SIZE(a)	(sizeof(a)/sizeof(a[0]))



struct data_info {
	unsigned int sample_rate;
	unsigned int channel;
	char *format;
};

struct output_ele {
	size_t ele_len;
	char ele[0];
};

typedef void (*output_callback)(struct output_ele *data, void *private_data);

struct sin_info {
	unsigned int amp;
	unsigned int freq;
	unsigned int time;
	struct data_info data;

	output_callback output;
	void *private_data;
};

typedef long long (*compute_total_data_func)(struct sin_info *info);
typedef int (*gen_sin_func)(struct sin_info *info);



struct formats_work {
	unsigned int format_id;
	char *format;
	unsigned int bits;
	compute_total_data_func compute_work;
	gen_sin_func work;
};


static long long total_data_s16_le(struct sin_info *info);
static int gen_sin_s16_le(struct sin_info *info);

struct formats_work format_works[] = {
	{SF_FORMAT_PCM_16, "S16_LE", sizeof(int16_t) * 8,
		total_data_s16_le, gen_sin_s16_le},
};

struct sin_info *get_sin_info(void)
{
	struct sin_info *info = NULL;

	info = malloc(sizeof(struct sin_info));
	if (!info)
		return NULL;

	memset(info, 0, sizeof(struct sin_info));


	return info;
}

int release_sin_info(struct sin_info *info)
{
	if (!info)
		return -1;

	free(info);

	return 0;
}

static long long total_data_s16_le(struct sin_info *info)
{
	return info->time * info->data.sample_rate * info->data.channel
		* sizeof(int16_t);
}

static int gen_sin_s16_le(struct sin_info *info)
{
	float angle_freq, t_delta;
	float resault;
	int16_t resault_s16;
	int i = 0, sample_bytes = 0;
	struct output_ele *p_ele = NULL;

	sample_bytes = info->data.channel * sizeof(uint16_t);
	p_ele = malloc(sizeof(struct output_ele) + sample_bytes);
	if (!p_ele)
		return -1;
	p_ele->ele_len = sample_bytes;

	angle_freq = 2 * M_PI * info->freq;
	t_delta = 1/(float)info->data.sample_rate;

	for (i = 0; i < info->data.sample_rate * info->time; i ++) {
		resault = info->amp * sin(angle_freq * i * t_delta);
		resault_s16 = (int16_t)resault;
		memcpy(p_ele->ele, &resault_s16, sizeof(int16_t));
		if (sample_bytes > sizeof(int16_t))
			memcpy((char *)(p_ele->ele + sizeof(int16_t)),
			       &resault_s16, sizeof(int16_t));
		info->output(p_ele, info->private_data);
	}

	free(p_ele);
	return 0;
}

int gen_sin_data(struct sin_info *info)
{
	int index = 0, ret = 0;

	if (!info->output)
		return -1;

	for (index = 0; index < ARRAY_SIZE(format_works); index ++) {
		if (!strcmp(info->data.format, format_works[index].format)) {
			if (format_works[index].work != NULL) {
				ret = format_works[index].work(info);
				if (ret < 0)
					return ret;
			} else
				return -1;
		}
	}

	if (index == ARRAY_SIZE(format_works))
		return -1;
}

void do_gs_work(struct output_ele *data, void *private_data)
{
	SNDFILE *fp = (SNDFILE *)private_data;
	sf_write_short(fp, (short *)data->ele,
		       (sf_count_t)(data->ele_len/sizeof(short))) ;
}

int main(int argc, char *argv[])
{
	struct sin_info *p_sin_info;
	SNDFILE *sndfile = NULL;
	SF_INFO file_info;

	file_info.samplerate = 16000;
	file_info.channels = 1;
	file_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;

	p_sin_info = get_sin_info();
	if (!p_sin_info) {
		printf("get sin info fail\n");
		return -1;
	}

	if (!sf_format_check(&file_info)) {
		printf("format wrong.\n");
		goto end;
	}

	sndfile = sf_open("./sine.wav", SFM_WRITE, &file_info);
	if (!sndfile) {
		printf("%s\n", sf_strerror(sndfile));
		return -1;
	}

	p_sin_info->amp = 16384;
	p_sin_info->time = 10;
	p_sin_info->freq = 1000;
	p_sin_info->private_data = (void *)sndfile;
	p_sin_info->data.sample_rate = 16000;
	p_sin_info->data.channel = 1;
	p_sin_info->data.format = "S16_LE";
	p_sin_info->output = do_gs_work;

	gen_sin_data(p_sin_info);


	sf_close(sndfile);
end:
	release_sin_info(p_sin_info);
	return 0;

}

amplitude和db

数字音频信号的参考值是最大幅度值,定为0db。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值