/*
* There is a lot of scrap here. It's not very well organized junk to
* provide minimal "emulation" of the kobj code for feeder objects.
*/
#ifndef _FEEDER_COMPAT_H_
#define _FEEDER_COMPAT_H_
#define KASSERT(x, y) assert(x)
#define CHN_LOCKASSERT(c)
struct feeder_class;
struct pcm_channel;
struct pcm_feeder;
/* Types for function pointers */
typedef int feeder_init_t(struct pcm_feeder *f);
typedef int feeder_free_t(struct pcm_feeder *f);
typedef int feeder_set_t(struct pcm_feeder *f, int what, int value);
typedef int feeder_get_t(struct pcm_feeder *f, int what);
typedef int feeder_feed_t(struct pcm_feeder *f, struct pcm_channel* c,
uint8_t *feed_buffer, uint32_t feed_bytes,
void *source);
typedef struct {
const char* name;
void *method;
} kobj_method_t;
#define KOBJMETHOD(x, y) { #x, y }
#define KOBJMETHOD_END { NULL, NULL }
#if 0
#define KOBJMETHOD(NAME, FUNC) \
{ \
&NAME##_desc, \
(kobjop_t) ((FUNC != (NAME##_t *)NULL) ? FUNC : NULL) \
}
#endif
struct pcmchan_matrix {
int id;
uint32_t channels, ext;
struct {
int type;
uint32_t members;
} map[SND_CHN_T_MAX + 1];
uint32_t mask;
int8_t offset[SND_CHN_T_MAX];
};
extern int feeder_volume_apply_matrix(struct pcm_feeder *,
struct pcmchan_matrix *);
/* feeder_matrix */
extern int feeder_matrix_default_id(uint32_t);
extern struct pcmchan_matrix *feeder_matrix_default_channel_map(uint32_t);
uint32_t feeder_matrix_default_format(uint32_t);
extern int feeder_matrix_format_id(uint32_t);
extern struct pcmchan_matrix *feeder_matrix_format_map(uint32_t);
extern struct pcmchan_matrix *feeder_matrix_id_map(int);
extern int feeder_matrix_setup(struct pcm_feeder *, struct pcmchan_matrix *,
struct pcmchan_matrix *);
extern int feeder_matrix_compare(struct pcmchan_matrix *,
struct pcmchan_matrix *);
extern int
feeder_matrix_oss_get_channel_order(struct pcmchan_matrix *,
unsigned long long *);
extern int
feeder_matrix_oss_set_channel_order(struct pcmchan_matrix *,
unsigned long long *);
struct pcm_feederdesc {
uint32_t type;
uint32_t in;
uint32_t out;
uint32_t flags;
int idx;
};
enum {
FEEDER_ROOT,
FEEDER_RATE,
FEEDER_FORMAT,
FEEDER_MATRIX,
FEEDER_VOLUME,
FEEDER_EQ,
FEEDER_STDIO,
FEEDER_LAST
};
/* feeder_eq */
enum {
FEEDEQ_CHANNELS,
FEEDEQ_RATE,
FEEDEQ_TREBLE,
FEEDEQ_BASS,
FEEDEQ_PREAMP,
FEEDEQ_STATE,
FEEDEQ_DISABLE,
FEEDEQ_ENABLE,
FEEDEQ_BYPASS,
FEEDEQ_UNKNOWN
};
int feeder_eq_validrate(uint32_t);
/* feeder_format */
enum {
FEEDFORMAT_CHANNELS
};
/* feeder_volume */
enum {
FEEDVOLUME_CLASS,
FEEDVOLUME_CHANNELS,
FEEDVOLUME_STATE,
FEEDVOLUME_ENABLE,
FEEDVOLUME_BYPASS
};
/* feeder_matrix */
/*enum {
FEEDMATRIX_TYPE,
FEEDMATRIX_RESET,
FEEDMATRIX_CHANNELS_IN,
FEEDMATRIX_CHANNELS_OUT,
FEEDMATRIX_SET_MAP
};
enum {
FEEDMATRIX_TYPE_NONE,
FEEDMATRIX_TYPE_AUTO,
FEEDMATRIX_TYPE_2X1,
FEEDMATRIX_TYPE_1X2,
FEEDMATRIX_TYPE_2X2
};
#define FEEDMATRIX_TYPE_STEREO_TO_MONO FEEDMATRIX_TYPE_2X1
#define FEEDMATRIX_TYPE_MONO_TO_STEREO FEEDMATRIX_TYPE_1X2
#define FEEDMATRIX_TYPE_SWAP_STEREO FEEDMATRIX_TYPE_2X2
#define FEEDMATRIX_MAP(x, y) ((((x) & 0x3f) << 6) | ((y) & 0x3f))
#define FEEDMATRIX_MAP_SRC(x) ((x) & 0x3f)
#define FEEDMATRIX_MAP_DST(x) (((x) >> 6) & 0x3f)*/
/* feeder_rate */
enum {
FEEDRATE_SRC,
FEEDRATE_DST,
FEEDRATE_QUALITY,
FEEDRATE_CHANNELS
};
#define FEEDRATE_RATEMIN 1
#define FEEDRATE_RATEMAX 2016000 /* 48000 * 42 */
#define FEEDRATE_MIN 1
#define FEEDRATE_MAX 0x7fffff /* sign 24bit ~ 8ghz ! */
#define FEEDRATE_ROUNDHZ 0
#define FEEDRATE_ROUNDHZ_MIN 0
#define FEEDRATE_ROUNDHZ_MAX 500
struct pcm_feeder {
void *data;
struct pcm_feeder *source;
struct pcm_feeder *parent;
struct pcm_feederdesc *desc;
struct feeder_class *class;
feeder_init_t *init;
feeder_free_t *free;
feeder_set_t *set;
feeder_get_t *get;
feeder_feed_t *feed;
};
struct feeder_class {
const char* name;
kobj_method_t* methods;
size_t size;
int align;
struct pcm_feederdesc *desc;
void *data;
};
#define FEEDER_DECLARE(feeder, pdata) \
static struct feeder_class feeder##_class = { \
.name = #feeder, \
.methods = feeder##_methods, \
.size = sizeof(struct pcm_feeder), \
.desc = feeder##_desc, \
.data = pdata \
}
static void*
class_get_method(struct feeder_class *cls, const char* name)
{
kobj_method_t * m = cls->methods;
while (m->name) {
if (strcmp(m->name, name) == 0)
return m->method;
m++;
}
return NULL;
}
static struct pcm_feeder*
feeder_create(struct feeder_class *cls, struct pcm_feederdesc *desc)
{
struct pcm_feeder *f = (struct pcm_feeder *)malloc(sizeof(*f));
f->source = NULL;
f->parent = NULL;
f->data = cls->data;
f->class = cls;
f->init = (feeder_init_t *)class_get_method(cls, "feeder_init");
f->free = (feeder_free_t *)class_get_method(cls, "feeder_free");
f->set = (feeder_set_t *)class_get_method(cls, "feeder_set");
f->get = (feeder_get_t *)class_get_method(cls, "feeder_get");
f->feed = (feeder_feed_t *)class_get_method(cls, "feeder_feed");
f->desc = (struct pcm_feederdesc *)malloc(sizeof(*(f->desc)));
if (desc != NULL)
*(f->desc) = *desc;
else
f->desc->in = f->desc->out = 0xffffffffU;
if (f->init && f->init(f)) {
free(f);
return NULL;
}
return f;
}
static void
feeder_destroy(struct pcm_feeder *f)
{
if (f->free)
f->free(f);
free(f->desc);
free(f);
}
static void
feeder_flush(struct pcm_feeder *f)
{
struct pcm_feeder *source;
while (f != NULL && f->parent != NULL)
f = f->parent;
while (f != NULL) {
source = f->source;
feeder_destroy(f);
f = source;
}
}
static void
feeder_dump(struct pcm_feeder *f)
{
int i;
while (f != NULL && f->source != NULL)
f = f->source;
i = 0;
while (f != NULL) {
i++;
fprintf(stderr, "%3d. %-2s%13s (0x%08x -> 0x%08x) %s\n", i,
(i == 1) ? "*" : " ", f->class->name,
f->desc->in, f->desc->out,
(f->parent != NULL) ? "+->" : "*");
f = f->parent;
}
}
#define FEEDER_CREATE(feeder, desc) feeder_create(& feeder ## _class, desc)
#define FEEDER_DESTROY(feeder) feeder_destroy(feeder)
#define FEEDER_FLUSH(feeder) feeder_flush(feeder)
#define FEEDER_DUMP(feeder) feeder_dump(feeder)
#define FEEDER_FEED(f, c, v, cnt, s) (f)->feed(f, c, v, cnt, s)
int FEEDER_SET(struct pcm_feeder *, int, int);
int FEEDER_GET(struct pcm_feeder *, int);
int
FEEDER_SET(struct pcm_feeder *f,
int what,
int value)
{
if (f->set)
return f->set(f, what, value);
return -1;
}
int
FEEDER_GET(struct pcm_feeder *f,
int what)
{
if (f->get)
return f->get(f, what);
return -1;
}
static struct pcm_feeder*
FEEDER_JOIN(struct pcm_feeder *src, struct pcm_feeder *dst, const char *fc)
{
if (dst->desc->in != src->desc->out)
errx(EX_DATAERR, "%s(): dst->desc->in=0x%08x != src->desc->out=0x%08x",
fc, dst->desc->in, src->desc->out);
if (dst->desc->out == 0xffffffff)
dst->desc->out = dst->desc->in;
dst->source = src;
src->parent = dst;
return dst;
}
struct pcm_channel {
struct pcm_feeder *feeder;
uint32_t feederflags;
uint32_t bufsize;
uint8_t *buffer;
int direction;
int volume[SND_VOL_C_MAX][SND_CHN_T_VOL_MAX];
FILE *in_fp, *out_fp;
};
#define PCMDIR_PLAY 1
#define PCMDIR_REC -1
static int
chn_setvolume_matrix(struct pcm_channel *c, int vc, int vt, int val)
{
int i;
/*KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX &&
(vc == SND_VOL_C_MASTER || (vc & 1)) &&
(vt == SND_CHN_T_VOL_0DB || (vt >= SND_CHN_T_BEGIN &&
vt <= SND_CHN_T_END)) && (vt != SND_CHN_T_VOL_0DB ||
(val >= SND_VOL_0DB_MIN && val <= SND_VOL_0DB_MAX)),
("%s(): invalid volume matrix c=%p vc=%d vt=%d val=%d",
__func__, c, vc, vt, val));*/
CHN_LOCKASSERT(c);
if (val < 0)
val = 0;
if (val > 100)
val = 100;
c->volume[vc][vt] = val;
/*
* Do relative calculation here and store it into class + 1
* to ease the job of feeder_volume.
*/
if (vc == SND_VOL_C_MASTER) {
for (vc = SND_VOL_C_BEGIN; vc <= SND_VOL_C_END;
vc += SND_VOL_C_STEP)
c->volume[SND_VOL_C_VAL(vc)][vt] =
SND_VOL_CALC_VAL(c->volume, vc, vt);
} else if (vc & 1) {
if (vt == SND_CHN_T_VOL_0DB) {
for (i = 0; i != SND_CHN_T_MAX; i++)
c->volume[SND_VOL_C_VAL(vc)][i] =
SND_VOL_CALC_VAL(c->volume, vc, i);
} else
c->volume[SND_VOL_C_VAL(vc)][vt] =
SND_VOL_CALC_VAL(c->volume, vc, vt);
}
return (val);
}
#define CHN_SETVOLUME(...) chn_setvolume_matrix(__VA_ARGS__)
#define CHN_GETVOLUME(x, y, z) ((x)->volume[y][z])
static int
chn_init(struct pcm_channel *c, int direction, uint32_t bufsize)
{
int i;
bzero(c, sizeof(*c));
c->volume[SND_VOL_C_MASTER][SND_CHN_T_VOL_0DB] = SND_VOL_0DB_MASTER;
c->volume[SND_VOL_C_PCM][SND_CHN_T_VOL_0DB] = SND_VOL_0DB_PCM;
for (i = 0; i != SND_CHN_T_MAX; i++) {
c->volume[SND_VOL_C_MASTER][i] = SND_VOL_0DB_MASTER;
CHN_SETVOLUME(c, SND_VOL_C_PCM, i,
c->volume[SND_VOL_C_PCM][SND_CHN_T_VOL_0DB]);
}
c->bufsize = bufsize;
c->buffer = malloc(bufsize);
c->direction = direction;
c->in_fp = stdin;
c->out_fp = stdout;
if (c->buffer == NULL)
return (ENOMEM);
return (0);
}
static void
chn_destroy(struct pcm_channel *c)
{
if (c == NULL)
return;
if (c->feeder != NULL)
FEEDER_FLUSH(c->feeder);
if (c->buffer != NULL)
free(c->buffer);
if (c->in_fp != stdin)
fclose(c->in_fp);
if (c->out_fp != stdout)
fclose(c->out_fp);
free(c);
}
static struct pcm_channel *
chn_create(int direction, uint32_t bufsize)
{
struct pcm_channel *c;
if (!(direction == PCMDIR_PLAY || direction == PCMDIR_REC))
errx(EINVAL, "invalid direction: 0x%08x", direction);
c = malloc(sizeof(*c));
if (c != NULL && chn_init(c, direction, bufsize) != 0) {
chn_destroy(c);
c = NULL;
}
return (c);
}
#define chn_addfeeder(x, y) chn_addfeeder_int(x, y, __func__)
static int
chn_addfeeder_int(struct pcm_channel *c, struct pcm_feeder *f, const char *fc)
{
if (c == NULL)
return (EINVAL);
c->feeder = (c->feeder != NULL) ? FEEDER_JOIN(c->feeder, f, fc) : f;
return (0);
}
#if 0
static struct pcm_feeder *
chn_findfeeder(struct pcm_channel *c, uint32_t type)
{
struct pcm_feeder *f;
f = c->feeder;
while (f != NULL && f->desc != NULL) {
if (f->desc->type == type)
return f;
f = f->source;
}
return NULL;
}
#endif
#define chn_feed(c) \
FEEDER_FEED((c)->feeder, c, (c)->buffer, (c)->bufsize, NULL)
#ifndef M_NOWAIT
#define M_NOWAIT 0
#endif
#ifndef M_ZERO
#define M_ZERO 1
#endif
#ifndef DSP_DEFAULT_SPEED
#define DSP_DEFAULT_SPEED 8000
#endif
#define MALLOC_DEFINE(x, y, z) static const int x = 0;
#define malloc(x, y, z) calloc(1, x)
#define free(x, y) free(x)
static __inline u_int min(u_int a, u_int b) { return ((a < b) ? a : b); }
static __inline u_int max(u_int a, u_int b) { return ((a < b) ? b : a); }
static __inline int32_t
sndbuf_zerodata(uint32_t fmt)
{
return ((fmt & AFMT_SIGNED) ? 0x00 : 0x80);
}
/*
* 14bit format scoring
* --------------------
*
* 13 12 11 10 9 8 2 1 0 offset
* +---+---+---+---+---+---+-------------+---+---+
* | X | X | X | X | X | X | X X X X X X | X | X |
* +---+---+---+---+---+---+-------------+---+---+
* | | | | | | | | |
* | | | | | | | | +--> signed?
* | | | | | | | |
* | | | | | | | +------> bigendian?
* | | | | | | |
* | | | | | | +---------------> total channels
* | | | | | |
* | | | | | +------------------------> AFMT_A_LAW
* | | | | |
* | | | | +----------------------------> AFMT_MU_LAW
* | | | |
* | | | +--------------------------------> AFMT_8BIT
* | | |
* | | +------------------------------------> AFMT_16BIT
* | |
* | +----------------------------------------> AFMT_24BIT
* |
* +--------------------------------------------> AFMT_32BIT
*/
#define score_signeq(s1, s2) (((s1) & 0x1) == ((s2) & 0x1))
#define score_endianeq(s1, s2) (((s1) & 0x2) == ((s2) & 0x2))
#define score_cheq(s1, s2) (((s1) & 0xfc) == ((s2) & 0xfc))
#define score_chgt(s1, s2) (((s1) & 0xfc) > ((s2) & 0xfc))
#define score_chlt(s1, s2) (((s1) & 0xfc) < ((s2) & 0xfc))
#define score_val(s1) ((s1) & 0x3f00)
#define score_cse(s1) ((s1) & 0x7f)
static int
fmtvalid(uint32_t fmt, uint32_t *fmtlist)
{
int i;
for (i = 0; fmtlist[i]; i++)
if (fmt == fmtlist[i])
return 1;
return 0;
}
static uint32_t
chn_fmtscore(uint32_t fmt)
{
uint32_t ret;
ret = 0;
if (fmt & AFMT_SIGNED)
ret |= 1 << 0;
if (fmt & AFMT_BIGENDIAN)
ret |= 1 << 1;
/*if (fmt & AFMT_STEREO)
ret |= (2 & 0x3f) << 2;
else
ret |= (1 & 0x3f) << 2;*/
ret |= (AFMT_CHANNEL(fmt) & 0x3f) << 2;
if (fmt & AFMT_A_LAW)
ret |= 1 << 8;
else if (fmt & AFMT_MU_LAW)
ret |= 1 << 9;
else if (fmt & AFMT_8BIT)
ret |= 1 << 10;
else if (fmt & AFMT_16BIT)
ret |= 1 << 11;
else if (fmt & AFMT_24BIT)
ret |= 1 << 12;
else if (fmt & AFMT_32BIT)
ret |= 1 << 13;
return ret;
}
static uint32_t
chn_fmtbestfunc(uint32_t fmt, uint32_t *fmts, int cheq)
{
uint32_t best, score, score2, oldscore;
int i;
if (fmt == 0 || fmts == NULL || fmts[0] == 0)
return 0;
if (fmtvalid(fmt, fmts))
return fmt;
best = 0;
score = chn_fmtscore(fmt);
oldscore = 0;
for (i = 0; fmts[i] != 0; i++) {
score2 = chn_fmtscore(fmts[i]);
if (cheq && !score_cheq(score, score2) &&
(score_chlt(score2, score) ||
(oldscore != 0 && score_chgt(score2, oldscore))))
continue;
if (oldscore == 0 ||
(score_val(score2) == score_val(score)) ||
(score_val(score2) == score_val(oldscore)) ||
(score_val(score2) > score_val(oldscore) &&
score_val(score2) < score_val(score)) ||
(score_val(score2) < score_val(oldscore) &&
score_val(score2) > score_val(score)) ||
(score_val(oldscore) < score_val(score) &&
score_val(score2) > score_val(oldscore))) {
if (score_val(oldscore) != score_val(score2) ||
score_cse(score) == score_cse(score2) ||
((score_cse(oldscore) != score_cse(score) &&
!score_endianeq(score, oldscore) &&
(score_endianeq(score, score2) ||
(!score_signeq(score, oldscore) &&
score_signeq(score, score2)))))) {
best = fmts[i];
oldscore = score2;
}
}
}
return best;
}
static uint32_t
chn_fmtbestbit(uint32_t fmt, uint32_t *fmts)
{
return chn_fmtbestfunc(fmt, fmts, 0);
}
static uint32_t
chn_fmtbestchannel(uint32_t fmt, uint32_t *fmts)
{
return chn_fmtbestfunc(fmt, fmts, 1);
}
static uint32_t
chn_fmtbest(uint32_t fmt, uint32_t *fmts)
{
uint32_t best1, best2;
uint32_t score, score1, score2;
if (fmtvalid(fmt, fmts))
return fmt;
best1 = chn_fmtbestchannel(fmt, fmts);
best2 = chn_fmtbestbit(fmt, fmts);
if (best1 != 0 && best2 != 0 && best1 != best2) {
/*if (fmt & AFMT_STEREO)*/
if (AFMT_CHANNEL(fmt) > 1)
return best1;
else {
score = score_val(chn_fmtscore(fmt));
score1 = score_val(chn_fmtscore(best1));
score2 = score_val(chn_fmtscore(best2));
if (score1 == score2 || score1 == score)
return best1;
else if (score2 == score)
return best2;
else if (score1 > score2)
return best1;
return best2;
}
} else if (best2 == 0)
return best1;
else
return best2;
}
#endif /* !_FEEDER_COMPAT_H_ */