音频编程 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。