sox_find_effect()主要是根据传入的效果器名字从effects.h文件中定义的效果器中进行遍历查找,最终目的是为了初始化结构体sox_effect_handler_t,关联一系列具体的处理接口函数。以norm为例进行说明。
sox_find_effect()函数调用关系
关键结构体
/**
Client API:
Effect handler information.
*/
struct sox_effect_handler_t {
char const * name; /**< Effect name */
char const * usage; /**< Short explanation of parameters accepted by effect */
unsigned int flags; /**< Combination of SOX_EFF_* flags */
sox_effect_handler_getopts getopts; /**< Called to parse command-line arguments (called once per effect). */
sox_effect_handler_start start; /**< Called to initialize effect (called once per flow). */
sox_effect_handler_flow flow; /**< Called to process samples. */
sox_effect_handler_drain drain; /**< Called to finish getting output after input is complete. */
sox_effect_handler_stop stop; /**< Called to shut down effect (called once per flow). */
sox_effect_handler_kill kill; /**< Called to shut down effect (called once per effect). */
size_t priv_size; /**< Size of private data SoX should pre-allocate for effect */
};
关键结构体sox_effect_handler_t 贯穿整个处理过程,主要是定义了一系列操作函数指针,主要通过名字区分不同的处理。
测试代码
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 比较两个字符串是否相同 */
int lsx_strcasecmp(const char * s1, const char * s2)
{
#if defined(HAVE_STRCASECMP)
return strcasecmp(s1, s2);
#elif defined(_MSC_VER)
return _stricmp(s1, s2);
#else
while (*s1 && (toupper(*s1) == toupper(*s2)))
s1++, s2++;
return toupper(*s1) - toupper(*s2);
#endif
}
#ifdef __GNUC__
#define LSX_API __attribute__ ((cdecl)) /* libSoX function */
#elif _MSC_VER
#define LSX_API __cdecl /* libSoX function */
#else
#define LSX_API /* libSoX function */
#endif
#define strcasecmp(s1, s2) lsx_strcasecmp((s1), (s2))
/* 定义相应的操作函数接口指针 */
struct sox_effect_handler_t {
char const * name; /**< Effect name */
char const * usage; /**< Short explanation of parameters accepted by effect */
// unsigned int flags; /**< Combination of SOX_EFF_* flags */
// sox_effect_handler_getopts getopts; /**< Called to parse command-line arguments (called once per effect). */
// sox_effect_handler_start start; /**< Called to initialize effect (called once per flow). */
// sox_effect_handler_flow flow; /**< Called to process samples. */
// sox_effect_handler_drain drain; /**< Called to finish getting output after input is complete. */
// sox_effect_handler_stop stop; /**< Called to shut down effect (called once per flow). */
// sox_effect_handler_kill kill; /**< Called to shut down effect (called once per effect). */
// size_t priv_size; /**< Size of private data SoX should pre-allocate for effect */
};
typedef struct sox_effect_handler_t sox_effect_handler_t;
typedef sox_effect_handler_t const * (LSX_API *sox_effect_fn_t)(void);
void *lsx_realloc(void *ptr, size_t newsize)
{
if (ptr && newsize == 0) {
free(ptr);
return NULL;
}
if ((ptr = realloc(ptr, newsize)) == NULL) {
printf("out of memory");
exit(2);
}
return ptr;
}
#define lsx_malloc(size) lsx_realloc(NULL, (size))
/* 帮助信息解析 */
char * lsx_usage_lines(char * * usage, char const * const * lines, size_t n)
{
if (!*usage) {
size_t i, len;
for (len = i = 0; i < n; len += strlen(lines[i++]) + 1);
*usage = lsx_malloc(len); /* FIXME: this memory will never be freed */
strcpy(*usage, lines[0]);
for (i = 1; i < n; ++i) {
strcat(*usage, "\n");
strcat(*usage, lines[i]);
}
}
return *usage;
}
#define array_length(a) (sizeof(a)/sizeof(a[0]))
sox_effect_handler_t const * lsx_gain_effect_fn(void)
{
static sox_effect_handler_t handler = {
"gain",
// NULL, SOX_EFF_GAIN,
// create, start, flow, drain, stop, NULL, sizeof(priv_t)
};
static char const * lines[] = {
"[-e|-b|-B|-r] [-n] [-l|-h] [gain-dB]",
"-e\t Equalise channels: peak to that with max peak;",
"-B\t Balance channels: rms to that with max rms; no clip protection",
"-b\t Balance channels: rms to that with max rms; clip protection",
"\t Note -Bn = -bn",
"-r\t Reclaim headroom (as much as possible without clipping); see -h",
"-n\t Norm file to 0dBfs(output precision); gain-dB, if present, usually <0",
"-l\t Use simple limiter",
"-h\t Apply attenuation for headroom for subsequent effects; gain-dB, if",
"\t present, is subject to reclaim by a subsequent gain -r",
"gain-dB\t Apply gain in dB",
};
static char * usage;
handler.usage = lsx_usage_lines(&usage, lines, array_length(lines));
return &handler;
}
/* norm效果器对应的操作函数接口 */
sox_effect_handler_t const * lsx_norm_effect_fn(void)
{
static sox_effect_handler_t handler;
handler = *lsx_gain_effect_fn(); // norm实际处理的是增益,关联增益效果器操作函数接口lsx_gain_effect_fn
handler.name = "norm";
handler.usage = "[level]";
// handler.getopts = norm_getopts;
return &handler;
}
/*----------------------------- Effects library ------------------------------*/
static sox_effect_fn_t s_sox_effect_fns[] = {
#define EFFECT(f) lsx_##f##_effect_fn, //名字
#include "effects.h"
#undef EFFECT
NULL
};
const sox_effect_fn_t*
sox_get_effect_fns(void)
{
return s_sox_effect_fns;
}
/* Find a named effect in the effects library */
/* 根据传入的效果器名字从effects.h文件中定义的效果器中进行遍历查找获取对应的操作函数接口 */
sox_effect_handler_t const * sox_find_effect(char const * name)
{
int e;
sox_effect_fn_t const * fns = sox_get_effect_fns(); // 解析effects.h中的效果器,获取对应效果器的操作函数接口
for (e = 0; fns[e]; ++e) {
const sox_effect_handler_t *eh = fns[e] ();
if (eh && eh->name && strcasecmp(eh->name, name) == 0) {
// 比较名字
printf("%s, %s\n", name, eh->name);
printf("%s\n", eh->usage);
return eh; /* Found it. */
}
}
return NULL;
}
int main()
{
sox_find_effect("norm");
}