//filter.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2012 * * This file is part of libroardsp a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * libroardsp is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "libroardsp.h" static struct _roardsp_filterlist { int id; char * name; int (* init )(struct roardsp_filter * filter, struct roar_stream * stream, int id); int (*uninit )(struct roardsp_filter * filter); int (*ctl )(struct roardsp_filter * filter, int cmd, void * data); int (*reset )(struct roardsp_filter * filter, int what); int (*calc [5][3])(struct roardsp_filter * filter, void * data, size_t samples); } _roardsp_filterlist[] = { {ROARDSP_FILTER_AMP, "AMP", roardsp_amp_init, roardsp_amp_uninit, roardsp_amp_ctl, roardsp_amp_reset, { {NULL, NULL, NULL},{roardsp_amp_calc8, NULL, NULL},{roardsp_amp_calc16, NULL, NULL}, {NULL, NULL, NULL},{roardsp_amp_calc32, NULL, NULL}}}, {ROARDSP_FILTER_ADD, "Add", roardsp_amp_init, roardsp_amp_uninit, roardsp_amp_ctl, roardsp_add_reset, { {NULL, NULL, NULL},{roardsp_add_calc8, NULL, NULL},{roardsp_add_calc16, NULL, NULL}, {NULL, NULL, NULL},{roardsp_add_calc32, NULL, NULL}}}, #ifdef ROAR_HAVE_LIBM {ROARDSP_FILTER_LOWP, "Lowpass", roardsp_lowp_init, roardsp_lowp_uninit, roardsp_lowp_ctl, roardsp_lowp_reset, { {NULL, NULL, NULL},{roardsp_lowp_calc8, NULL, NULL},{roardsp_lowp_calc16, NULL, NULL}, {NULL, NULL, NULL},{roardsp_lowp_calc32, NULL, NULL}}}, {ROARDSP_FILTER_HIGHP, "Highpass", roardsp_highp_init, roardsp_highp_uninit, roardsp_highp_ctl, roardsp_highp_reset, { {NULL, NULL, NULL},{roardsp_highp_calc8, NULL, NULL},{roardsp_highp_calc16, NULL, NULL}, {NULL, NULL, NULL},{roardsp_highp_calc32, NULL, NULL}}}, #endif {ROARDSP_FILTER_QUANTIFY, "Quantifier", roardsp_quantify_init, NULL, roardsp_quantify_ctl, roardsp_quantify_reset, { {NULL, NULL, NULL},{roardsp_quantify_calc8, NULL, NULL},{roardsp_quantify_calc16, NULL, NULL}, {NULL, NULL, NULL},{roardsp_quantify_calc32, NULL, NULL}}}, {ROARDSP_FILTER_CLIP, "Clip", roardsp_clip_init, roardsp_clip_uninit, roardsp_clip_ctl, roardsp_clip_reset, { {NULL, NULL, NULL},{roardsp_clip_calc8, NULL, NULL},{roardsp_clip_calc16, NULL, NULL}, {NULL, NULL, NULL},{roardsp_clip_calc32, NULL, NULL}}}, {ROARDSP_FILTER_DOWNMIX, "downmix", roardsp_quantify_init, NULL, roardsp_downmix_ctl, roardsp_downmix_reset, { {NULL, NULL, NULL},{NULL, NULL, NULL},{NULL, NULL, roardsp_downmix_calc162},{NULL, NULL, NULL},{NULL, NULL, NULL}}}, {ROARDSP_FILTER_DCBLOCK, "DCBlock", roardsp_dcblock_init, NULL, NULL, roardsp_dcblock_reset, { {NULL, NULL, NULL},{NULL, NULL, NULL},{roardsp_dcblock_calc16, NULL, NULL},{NULL, NULL, NULL},{NULL, NULL, NULL}}}, {ROARDSP_FILTER_SWAP, "Swap", roardsp_swap_init, roardsp_swap_uninit, roardsp_swap_ctl, roardsp_swap_reset, { {NULL, NULL, NULL},{NULL, NULL, roardsp_swap_calc82},{NULL, NULL, roardsp_swap_calc162}, {NULL, NULL, NULL},{NULL, NULL, roardsp_swap_calc322}}}, {ROARDSP_FILTER_AGC, "AGC", roardsp_agc_init, roardsp_agc_uninit, roardsp_agc_ctl, roardsp_agc_reset, { {NULL, NULL, NULL},{NULL, NULL, NULL},{NULL, NULL, NULL},{NULL, NULL, NULL},{NULL, NULL, NULL}}}, #ifdef ROAR_HAVE_SPEEX_FILTER {ROARDSP_FILTER_SPEEX_PREP, "SpeexPrep", roardsp_speex_prep_init, roardsp_speex_prep_uninit, roardsp_speex_prep_ctl, roardsp_speex_prep_reset, { {NULL, NULL, NULL},{NULL, NULL, NULL},{NULL, roardsp_speex_prep_calc161, NULL},{NULL, NULL, NULL},{NULL, NULL, NULL}}}, #endif #ifdef ROAR_HAVE_LIBM {ROARDSP_FILTER_RESPONSE_CURVE, "ResponseCurve", roardsp_responsecurve_init, roardsp_responsecurve_uninit, roardsp_responsecurve_ctl, roardsp_responsecurve_reset, { {NULL, NULL, NULL},{roardsp_responsecurve_calc8, NULL, NULL},{roardsp_responsecurve_calc16, NULL, NULL}, {NULL, NULL, NULL},{roardsp_responsecurve_calc32, NULL, NULL} }}, {ROARDSP_FILTER_GOERTZEL, "Goertzel", roardsp_goertzel_init, roardsp_goertzel_uninit, roardsp_goertzel_ctl, roardsp_goertzel_reset, { {NULL, NULL, NULL},{roardsp_goertzel_calc8, NULL, NULL},{roardsp_goertzel_calc16, NULL, NULL}, {NULL, NULL, NULL},{roardsp_goertzel_calc32, NULL, NULL} }}, #endif {-1, NULL, NULL, NULL, NULL, NULL, { // ? 8Bit 16Bit 24Bit 32Bit // 0B:n 1 2 1B:n 1 2 2B:n 1 2 3B:n 1 2 4B:n 1 2 {NULL, NULL, NULL},{NULL, NULL, NULL},{NULL, NULL, NULL},{NULL, NULL, NULL},{NULL, NULL, NULL}}} }; int roardsp_filter_str2id(const char * str) { struct _roardsp_filterlist * l = _roardsp_filterlist; while ( l->id != -1 ) { if ( strcasecmp(l->name, str) == 0 ) return l->id; l++; } roar_err_set(ROAR_ERROR_NOENT); return -1; } const char * roardsp_filter_id2str(const int id) { struct _roardsp_filterlist * l = _roardsp_filterlist; while ( l->id != -1 ) { if ( l->id == id ) return l->name; l++; } roar_err_set(ROAR_ERROR_NOENT); return NULL; } int roardsp_filter_new (struct roardsp_filter ** filter, struct roar_stream * stream, int id) { struct roardsp_filter * n; int ret; int error; if ( filter == NULL || stream == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } *filter = NULL; // just to be sure n = roar_mm_malloc(sizeof(struct roardsp_filter)); if ( n == NULL ) return -1; if ( (ret = roardsp_filter_init(n, stream, id)) == -1 ) { error = roar_error; roar_mm_free(n); roar_err_set(error); return -1; } n->flags |= ROARDSP_FFLAG_FREE; *filter = n; return ret; } int roardsp_filter_init (struct roardsp_filter * filter, struct roar_stream * stream, int id) { struct _roardsp_filterlist * l = _roardsp_filterlist; int bytes; int (*calc)(struct roardsp_filter * filter, void * data, size_t samples) = NULL; if ( filter == NULL || stream == NULL ) { ROAR_DBG("roardsp_filter_init(*) = -1 // filter or stream is NULL"); roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( id < 0 ) { roar_err_set(ROAR_ERROR_INVAL); return -1; } ROAR_DBG("roardsp_filter_init(filter=%p, stream=%p, id=%i) = ?", filter, stream, id); memset(filter, 0, sizeof(struct roardsp_filter)); filter->channels = stream->info.channels; filter->bits = stream->info.bits; filter->rate = stream->info.rate; bytes = stream->info.bits / 8; while ( l->id != id ) { if ( l->id == -1 ) { roar_err_set(ROAR_ERROR_NOENT); return -1; } l++; } filter->uninit = l->uninit; filter->ctl = l->ctl; filter->reset = l->reset; ROAR_DBG("roardsp_filter_init(filter=%p, stream=%p, id=%i): bytes=%i", filter, stream, id, bytes); if ( filter->channels < 3 ) calc = l->calc[bytes][filter->channels]; if ( calc == NULL ) calc = l->calc[bytes][0]; // for n channels if ( calc == NULL ) { ROAR_DBG("roardsp_filter_init(*) = -1 // no calc code"); roar_err_set(ROAR_ERROR_NOTSUP); return -1; } filter->calc = calc; if ( l->init != NULL ) { ROAR_DBG("roardsp_filter_init(*) = ? // execing init"); return l->init(filter, stream, id); } ROAR_DBG("roardsp_filter_init(*) = 0 // no init"); return 0; } int roardsp_filter_uninit(struct roardsp_filter * filter) { int ret = 0; if ( filter == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( filter->uninit != NULL ) ret = filter->uninit(filter); if ( filter->flags & ROARDSP_FFLAG_FREE ) { roar_mm_free(filter); } else { memset(filter, 0, sizeof(struct roardsp_filter)); } return ret; } int roardsp_filter_calc (struct roardsp_filter * filter, void * data, size_t len) { int ret = 0; if ( filter == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( data == NULL && len != 0 ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( filter->calc != NULL ) ret = filter->calc(filter, data, len); return ret; } int roardsp_filter_ctl (struct roardsp_filter * filter, int cmd, void * data) { if ( filter == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( filter->ctl != NULL ) return filter->ctl(filter, cmd, data); roar_err_set(ROAR_ERROR_NOSYS); return -1; } int roardsp_filter_reset (struct roardsp_filter * filter, int what) { if ( filter == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( filter->reset != NULL ) return filter->reset(filter, what); roar_err_set(ROAR_ERROR_NOSYS); return -1; } //ll