1
mirror of https://github.com/mpv-player/mpv synced 2024-12-24 07:33:46 +01:00

Changes includes:

- Improved runtime control system
- 3 New filter panning, compressor/limiter and a noise gate
  - The compressor/limiter and the noise gate are not yet finished
  - The panning filter does combined mixing and channel routing and
    can be used to down-mix from stereo to mono (for example)
- Improvements to volume and channel
  - volume now has a very good soft clipping using sin()
  - channel can handle generic routing of audio data
- Conversion of all filters to handle floating point data
- Cleanup of message printing
- Fix for the sig 11 bug reported by Denes


git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@8608 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
anders 2002-12-28 13:59:53 +00:00
parent 0e9c0e8aa2
commit 6adaa78ee9
15 changed files with 1473 additions and 440 deletions

View File

@ -2,7 +2,7 @@ include ../config.mak
LIBNAME = libaf.a
SRCS=af.c af_mp.c af_dummy.c af_delay.c af_channels.c af_format.c af_resample.c window.c filter.c af_volume.c af_equalizer.c
SRCS=af.c af_mp.c af_dummy.c af_delay.c af_channels.c af_format.c af_resample.c window.c filter.c af_volume.c af_equalizer.c af_tools.c af_comp.c af_gate.c af_pan.c
OBJS=$(SRCS:.c=.o)

View File

@ -16,6 +16,9 @@ extern af_info_t af_info_format;
extern af_info_t af_info_resample;
extern af_info_t af_info_volume;
extern af_info_t af_info_equalizer;
extern af_info_t af_info_gate;
extern af_info_t af_info_comp;
extern af_info_t af_info_pan;
static af_info_t* filter_list[]={ \
&af_info_dummy,\
@ -25,6 +28,9 @@ static af_info_t* filter_list[]={ \
&af_info_resample,\
&af_info_volume,\
&af_info_equalizer,\
&af_info_gate,\
&af_info_comp,\
&af_info_pan,\
NULL \
};
@ -72,7 +78,7 @@ af_instance_t* af_create(af_stream_t* s, char* name)
// Allocate space for the new filter and reset all pointers
af_instance_t* new=malloc(sizeof(af_instance_t));
if(!new){
af_msg(AF_MSG_ERROR,"Could not allocate memory\n");
af_msg(AF_MSG_ERROR,"[libaf] Could not allocate memory\n");
return NULL;
}
memset(new,0,sizeof(af_instance_t));
@ -88,13 +94,14 @@ af_instance_t* af_create(af_stream_t* s, char* name)
non-reentrant */
if(new->info->flags & AF_FLAGS_NOT_REENTRANT){
if(af_get(s,name)){
af_msg(AF_MSG_ERROR,"There can only be one instance of the filter '%s' in each stream\n",name);
af_msg(AF_MSG_ERROR,"[libaf] There can only be one instance of"
" the filter '%s' in each stream\n",name);
free(new);
return NULL;
}
}
af_msg(AF_MSG_VERBOSE,"Adding filter %s \n",name);
af_msg(AF_MSG_VERBOSE,"[libaf] Adding filter %s \n",name);
// Initialize the new filter
if(AF_OK == new->info->open(new) &&
@ -108,7 +115,8 @@ af_instance_t* af_create(af_stream_t* s, char* name)
}
free(new);
af_msg(AF_MSG_ERROR,"Couldn't create or open audio filter '%s'\n",name);
af_msg(AF_MSG_ERROR,"[libaf] Couldn't create or open audio filter '%s'\n",
name);
return NULL;
}
@ -165,6 +173,9 @@ void af_remove(af_stream_t* s, af_instance_t* af)
{
if(!af) return;
// Print friendly message
af_msg(AF_MSG_VERBOSE,"[libaf] Removing filter %s \n",af->info->name);
// Notify filter before changing anything
af->control(af,AF_CONTROL_PRE_DESTROY,0);
@ -234,8 +245,9 @@ int af_reinit(af_stream_t* s, af_instance_t* af)
// Create format filter
if(NULL == (new = af_prepend(s,af,"format")))
return AF_ERROR;
// Set output format
if(AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT,&in)))
// Set output bits per sample
if(AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT_BPS,&in.bps)) ||
AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT_FMT,&in.format)))
return rv;
// Initialize format filter
if(!new->prev)
@ -245,8 +257,11 @@ int af_reinit(af_stream_t* s, af_instance_t* af)
if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in)))
return rv;
}
if(!new) // Should _never_ happen
if(!new){ // Should _never_ happen
af_msg(AF_MSG_ERROR,"[libaf] Unable to correct audio format. "
"This error should never uccur, please send bugreport.\n");
return AF_ERROR;
}
af=new;
}
break;
@ -264,10 +279,17 @@ int af_reinit(af_stream_t* s, af_instance_t* af)
break;
}
default:
af_msg(AF_MSG_ERROR,"Reinitialization did not work, audio filter '%s' returned error code %i\n",af->info->name,rv);
af_msg(AF_MSG_ERROR,"[libaf] Reinitialization did not work, audio"
" filter '%s' returned error code %i\n",af->info->name,rv);
return AF_ERROR;
}
af=af->next;
// Check if there are any filters left in the list
if(NULL == af){
if(!af_append(s,s->first,"dummy"))
return -1;
}
else
af=af->next;
}while(af);
return AF_OK;
}
@ -315,7 +337,7 @@ int af_init(af_stream_t* s)
}
}
}
// Init filters
if(AF_OK != af_reinit(s,s->first))
return -1;
@ -340,7 +362,8 @@ int af_init(af_stream_t* s)
}
}
// Init the new filter
if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE,&(s->output.rate))))
if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE_RATE,
&(s->output.rate))))
return -1;
if(AF_OK != af_reinit(s,af))
return -1;
@ -368,7 +391,8 @@ int af_init(af_stream_t* s)
else
af = s->last;
// Init the new filter
if(!af ||(AF_OK != af->control(af,AF_CONTROL_FORMAT,&(s->output))))
if(!af ||(AF_OK != af->control(af,AF_CONTROL_FORMAT_BPS,&(s->output.bps)))
|| (AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT,&(s->output.format))))
return -1;
if(AF_OK != af_reinit(s,af))
return -1;
@ -383,7 +407,8 @@ int af_init(af_stream_t* s)
(s->last->data->nch != s->output.nch) ||
(s->last->data->rate != s->output.rate)) {
// Something is stuffed audio out will not work
af_msg(AF_MSG_ERROR,"Unable to setup filter system can not meet sound-card demands, please report this error on MPlayer development mailing list. \n");
af_msg(AF_MSG_ERROR,"[libaf] Unable to setup filter system can not"
" meet sound-card demands, please send bugreport. \n");
af_uninit(s);
return -1;
}
@ -493,6 +518,10 @@ int af_calc_insize_constrained(af_stream_t* s, int len,
mul.d *= af->mul.d;
af=af->next;
}while(af);
// Sanity check
if(!mul.n || !mul.d)
return -1;
in = t * (((len/t) * mul.d - 1)/mul.n);
if(in>max_insize) in=t*(max_insize/t);
@ -531,14 +560,15 @@ inline int af_resize_local_buffer(af_instance_t* af, af_data_t* data)
{
// Calculate new length
register int len = af_lencalc(af->mul,data);
af_msg(AF_MSG_VERBOSE,"Reallocating memory in module %s, old len = %i, new len = %i\n",af->info->name,af->data->len,len);
af_msg(AF_MSG_VERBOSE,"[libaf] Reallocating memory in module %s, "
"old len = %i, new len = %i\n",af->info->name,af->data->len,len);
// If there is a buffer free it
if(af->data->audio)
free(af->data->audio);
// Create new buffer and check that it is OK
af->data->audio = malloc(len);
if(!af->data->audio){
af_msg(AF_MSG_FATAL,"Could not allocate memory \n");
af_msg(AF_MSG_FATAL,"[libaf] Could not allocate memory \n");
return AF_ERROR;
}
af->data->len=len;

View File

@ -180,6 +180,19 @@ int af_resize_local_buffer(af_instance_t* af, af_data_t* data);
needed */
int af_lencalc(frac_t mul, af_data_t* data);
/* Helper function used to convert to gain value from dB. Returns
AF_OK if of and AF_ERROR if fail */
int af_from_dB(int n, float* in, float* out, float k, float mi, float ma);
/* Helper function used to convert from gain value to dB. Returns
AF_OK if of and AF_ERROR if fail */
int af_to_dB(int n, float* in, float* out, float k);
/* Helper function used to convert from ms to sample time*/
int af_from_ms(int n, float* in, float* out, int rate, float mi, float ma);
/* Helper function used to convert from sample time to ms */
int af_to_ms(int n, float* in, float* out, int rate);
/* Helper function for testing the output format */
int af_test_output(struct af_instance_s* af, af_data_t* out);
/* Memory reallocation macro: if a local buffer is used (i.e. if the
filter doesn't operate on the incoming buffer this macro must be
called to ensure the buffer is big enough. */

View File

@ -10,6 +10,15 @@
#include "af.h"
#define FR 0
#define TO 1
typedef struct af_channels_s{
int route[AF_NCH][2];
int nr;
int router;
}af_channels_t;
// Local function for copying data
void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, int bps)
{
@ -67,41 +76,140 @@ void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, i
break;
}
default:
af_msg(AF_MSG_ERROR,"[channels] Unsupported number of bytes/sample: %i please report this error on the MPlayer mailing list. \n",bps);
af_msg(AF_MSG_ERROR,"[channels] Unsupported number of bytes/sample: %i"
" please report this error on the MPlayer mailing list. \n",bps);
}
}
// Make sure the routes are sane
static int check_routes(af_channels_t* s, int nin, int nout)
{
int i;
if((s->nr < 1) || (s->nr > AF_NCH)){
af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs musst be"
" between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
return AF_ERROR;
}
for(i=0;i<s->nr;i++){
if((s->route[i][FR] >= nin) || (s->route[i][TO] >= nout)){
af_msg(AF_MSG_ERROR,"[channels] Invalid routing in pair nr. %i.\n", i);
return AF_ERROR;
}
}
return AF_OK;
}
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
af_channels_t* s = af->setup;
switch(cmd){
case AF_CONTROL_REINIT:
// Make sure this filter isn't redundant
if(af->data->nch == ((af_data_t*)arg)->nch)
return AF_DETACH;
// Set default channel assignment
if(!s->router){
int i;
// Make sure this filter isn't redundant
if(af->data->nch == ((af_data_t*)arg)->nch)
return AF_DETACH;
// If mono: fake stereo
if(((af_data_t*)arg)->nch == 1){
s->nr = min(af->data->nch,2);
for(i=0;i<s->nr;i++){
s->route[i][FR] = 0;
s->route[i][TO] = i;
}
}
else{
s->nr = min(af->data->nch, ((af_data_t*)arg)->nch);
for(i=0;i<s->nr;i++){
s->route[i][FR] = i;
s->route[i][TO] = i;
}
}
}
af->data->rate = ((af_data_t*)arg)->rate;
af->data->format = ((af_data_t*)arg)->format;
af->data->bps = ((af_data_t*)arg)->bps;
af->mul.n = af->data->nch;
af->mul.d = ((af_data_t*)arg)->nch;
return AF_OK;
return check_routes(s,((af_data_t*)arg)->nch,af->data->nch);
case AF_CONTROL_COMMAND_LINE:{
int nch = 0;
sscanf((char*)arg,"%i",&nch);
return af->control(af,AF_CONTROL_CHANNELS,&nch);
}
case AF_CONTROL_CHANNELS:
int n = 0;
// Check number of channels and number of routing pairs
sscanf(arg, "%i:%i%n", &nch, &s->nr, &n);
// If router scan commandline for routing pairs
if(s->nr){
char* cp = &((char*)arg)[n];
int ch = 0;
// Sanity check
if((s->nr < 1) || (s->nr > AF_NCH)){
af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs musst be"
" between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
}
s->router = 1;
// Scan for pairs on commandline
while((*cp == ':') && (ch < s->nr)){
sscanf(cp, ":%i:%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n);
af_msg(AF_MSG_DEBUG0,"[channels] Routing from channel %i to"
" channel %i\n",s->route[ch][FR],s->route[ch][TO]);
cp = &cp[n];
ch++;
}
}
if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch))
return AF_ERROR;
return AF_OK;
}
case AF_CONTROL_CHANNELS | AF_CONTROL_SET:
// Reinit must be called after this function has been called
// Sanity check
if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > 6){
af_msg(AF_MSG_ERROR,"[channels] The number of output channels must be between 1 and 6. Current value is%i \n",((int*)arg)[0]);
af_msg(AF_MSG_ERROR,"[channels] The number of output channels must be"
" between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
return AF_ERROR;
}
af->data->nch=((int*)arg)[0];
af_msg(AF_MSG_VERBOSE,"[channels] Changing number of channels to %i\n",af->data->nch);
if(!s->router)
af_msg(AF_MSG_VERBOSE,"[channels] Changing number of channels"
" to %i\n",af->data->nch);
return AF_OK;
case AF_CONTROL_CHANNELS | AF_CONTROL_GET:
*(int*)arg = af->data->nch;
return AF_OK;
case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{
int ch = ((af_control_ext_t*)arg)->ch;
int* route = ((af_control_ext_t*)arg)->arg;
s->route[ch][FR] = route[FR];
s->route[ch][TO] = route[TO];
return AF_OK;
}
case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{
int ch = ((af_control_ext_t*)arg)->ch;
int* route = ((af_control_ext_t*)arg)->arg;
route[FR] = s->route[ch][FR];
route[TO] = s->route[ch][TO];
return AF_OK;
}
case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET:
s->nr = *(int*)arg;
return AF_OK;
case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET:
*(int*)arg = s->nr;
return AF_OK;
case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET:
s->router = *(int*)arg;
return AF_OK;
case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET:
*(int*)arg = s->router;
return AF_OK;
}
return AF_UNKNOWN;
@ -110,6 +218,8 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
// Deallocate memory
static void uninit(struct af_instance_s* af)
{
if(af->setup)
free(af->setup);
if(af->data)
free(af->data);
}
@ -117,32 +227,21 @@ static void uninit(struct af_instance_s* af)
// Filter data through filter
static af_data_t* play(struct af_instance_s* af, af_data_t* data)
{
af_data_t* c = data; // Current working data
af_data_t* l = af->data; // Local data
af_data_t* c = data; // Current working data
af_data_t* l = af->data; // Local data
af_channels_t* s = af->setup;
int i;
if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
return NULL;
// Reset unused channels if nch in < nch out
if(af->mul.n > af->mul.d)
memset(l->audio,0,(c->len*af->mul.n)/af->mul.d);
// Reset unused channels
memset(l->audio,0,(c->len*af->mul.n)/af->mul.d);
// Special case always output L & R
if(c->nch == 1){
copy(c->audio,l->audio,1,0,l->nch,0,c->len,c->bps);
copy(c->audio,l->audio,1,0,l->nch,1,c->len,c->bps);
}
else{
int i;
if(l->nch < c->nch){
for(i=0;i<l->nch;i++) // Truncates R if l->nch == 1 not good need mixing
copy(c->audio,l->audio,c->nch,i,l->nch,i,c->len,c->bps);
}
else{
for(i=0;i<c->nch;i++)
copy(c->audio,l->audio,c->nch,i,l->nch,i,c->len,c->bps);
}
}
if(AF_OK == check_routes(s,c->nch,l->nch))
for(i=0;i<s->nr;i++)
copy(c->audio,l->audio,c->nch,s->route[i][FR],
l->nch,s->route[i][TO],c->len,c->bps);
// Set output data
c->audio = l->audio;
@ -160,7 +259,8 @@ static int open(af_instance_t* af){
af->mul.n=1;
af->mul.d=1;
af->data=calloc(1,sizeof(af_data_t));
if(af->data == NULL)
af->setup=calloc(1,sizeof(af_channels_t));
if((af->data == NULL) || (af->setup == NULL))
return AF_ERROR;
return AF_OK;
}

161
libaf/af_comp.c Normal file
View File

@ -0,0 +1,161 @@
/*=============================================================================
//
// This software has been released under the terms of the GNU Public
// license. See http://www.gnu.org/copyleft/gpl.html for details.
//
// Copyright 2002 Anders Johansson ajh@atri.curtin.edu.au
//
//=============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include "af.h"
// Data for specific instances of this filter
typedef struct af_comp_s
{
int enable[AF_NCH]; // Enable/disable / channel
float time[AF_NCH]; // Forgetting factor for power estimate
float pow[AF_NCH]; // Estimated power level [dB]
float tresh[AF_NCH]; // Threshold [dB]
float attack[AF_NCH]; // Attack time [ms]
float release[AF_NCH]; // Release time [ms]
float ratio[AF_NCH]; // Compression ratio
}af_comp_t;
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
af_comp_t* s = (af_comp_t*)af->setup;
int i;
switch(cmd){
case AF_CONTROL_REINIT:
// Sanity check
if(!arg) return AF_ERROR;
af->data->rate = ((af_data_t*)arg)->rate;
af->data->nch = ((af_data_t*)arg)->nch;
af->data->format = AF_FORMAT_F | AF_FORMAT_NE;
af->data->bps = 4;
// Time constant set to 0.1s
// s->alpha = (1.0/0.2)/(2.0*M_PI*(float)((af_data_t*)arg)->rate);
return af_test_output(af,(af_data_t*)arg);
case AF_CONTROL_COMMAND_LINE:{
/* float v=-10.0; */
/* float vol[AF_NCH]; */
/* float s=0.0; */
/* float clipp[AF_NCH]; */
/* int i; */
/* sscanf((char*)arg,"%f:%f", &v, &s); */
/* for(i=0;i<AF_NCH;i++){ */
/* vol[i]=v; */
/* clipp[i]=s; */
/* } */
/* if(AF_OK != control(af,AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET, clipp)) */
/* return AF_ERROR; */
/* return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol); */
}
case AF_CONTROL_COMP_ON_OFF | AF_CONTROL_SET:
memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int));
return AF_OK;
case AF_CONTROL_COMP_ON_OFF | AF_CONTROL_GET:
memcpy((int*)arg,s->enable,AF_NCH*sizeof(int));
return AF_OK;
case AF_CONTROL_COMP_THRESH | AF_CONTROL_SET:
return af_from_dB(AF_NCH,(float*)arg,s->tresh,20.0,-60.0,-1.0);
case AF_CONTROL_COMP_THRESH | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->tresh,(float*)arg,10.0);
case AF_CONTROL_COMP_ATTACK | AF_CONTROL_SET:
return af_from_ms(AF_NCH,(float*)arg,s->attack,af->data->rate,500.0,0.1);
case AF_CONTROL_COMP_ATTACK | AF_CONTROL_GET:
return af_to_ms(AF_NCH,s->attack,(float*)arg,af->data->rate);
case AF_CONTROL_COMP_RELEASE | AF_CONTROL_SET:
return af_from_ms(AF_NCH,(float*)arg,s->release,af->data->rate,3000.0,10.0);
case AF_CONTROL_COMP_RELEASE | AF_CONTROL_GET:
return af_to_ms(AF_NCH,s->release,(float*)arg,af->data->rate);
case AF_CONTROL_COMP_RATIO | AF_CONTROL_SET:
for(i=0;i<AF_NCH;i++)
s->ratio[i] = clamp(((float*)arg)[i],1.0,10.0);
return AF_OK;
case AF_CONTROL_COMP_RATIO | AF_CONTROL_GET:
for(i=0;i<AF_NCH;i++)
((float*)arg)[i] = s->ratio[i];
return AF_OK;
}
return AF_UNKNOWN;
}
// Deallocate memory
static void uninit(struct af_instance_s* af)
{
if(af->data)
free(af->data);
if(af->setup)
free(af->setup);
}
// Filter data through filter
static af_data_t* play(struct af_instance_s* af, af_data_t* data)
{
af_data_t* c = data; // Current working data
af_comp_t* s = (af_comp_t*)af->setup; // Setup for this instance
float* a = (float*)c->audio; // Audio data
int len = c->len/4; // Number of samples
int ch = 0; // Channel counter
register int nch = c->nch; // Number of channels
register int i = 0;
// Compress/expand
for(ch = 0; ch < nch ; ch++){
if(s->enable[ch]){
float t = 1.0 - s->time[ch];
for(i=ch;i<len;i+=nch){
register float x = a[i];
register float pow = x*x;
s->pow[ch] = t*s->pow[ch] +
pow*s->time[ch]; // LP filter
if(pow < s->pow[ch]){
;
}
else{
;
}
a[i] = x;
}
}
}
return c;
}
// Allocate memory and set function pointers
static int open(af_instance_t* af){
af->control=control;
af->uninit=uninit;
af->play=play;
af->mul.n=1;
af->mul.d=1;
af->data=calloc(1,sizeof(af_data_t));
af->setup=calloc(1,sizeof(af_comp_t));
if(af->data == NULL || af->setup == NULL)
return AF_ERROR;
return AF_OK;
}
// Description of this filter
af_info_t af_info_comp = {
"Compressor/expander audio filter",
"comp",
"Anders",
"",
AF_FLAGS_NOT_REENTRANT,
open
};

View File

@ -27,14 +27,15 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
af->data->format = ((af_data_t*)arg)->format;
af->data->bps = ((af_data_t*)arg)->bps;
return af->control(af,AF_CONTROL_DELAY_SET_LEN,&((af_delay_t*)af->setup)->tlen);
return af->control(af,AF_CONTROL_DELAY_LEN | AF_CONTROL_SET,
&((af_delay_t*)af->setup)->tlen);
}
case AF_CONTROL_COMMAND_LINE:{
float d = 0;
sscanf((char*)arg,"%f",&d);
return af->control(af,AF_CONTROL_DELAY_SET_LEN,&d);
return af->control(af,AF_CONTROL_DELAY_LEN | AF_CONTROL_SET,&d);
}
case AF_CONTROL_DELAY_SET_LEN:{
case AF_CONTROL_DELAY_LEN | AF_CONTROL_SET:{
af_delay_t* s = (af_delay_t*)af->setup;
void* bt = s->buf; // Old buffer
int lt = s->len; // Old len
@ -50,8 +51,7 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
// Set new len and allocate new buffer
s->tlen = *((float*)arg);
af->delay = s->tlen * 1000.0;
// s->len = af->data->rate*af->data->bps*af->data->nch*(int)s->tlen;
s->len = ((int)(af->data->rate*s->tlen))*af->data->bps*af->data->nch;
s->len = af->data->rate*af->data->bps*af->data->nch*(int)s->tlen;
s->buf = malloc(s->len);
af_msg(AF_MSG_DEBUG0,"[delay] Delaying audio output by %0.2fs\n",s->tlen);
af_msg(AF_MSG_DEBUG1,"[delay] Delaying audio output by %i bytes\n",s->len);
@ -74,6 +74,9 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
}
return AF_OK;
}
case AF_CONTROL_DELAY_LEN | AF_CONTROL_GET:
*((float*)arg) = ((af_delay_t*)af->setup)->tlen;
return AF_OK;
}
return AF_UNKNOWN;
}

View File

@ -22,16 +22,27 @@
#include <math.h>
#include "af.h"
#include "equalizer.h"
#define NCH AF_NCH // Number of channels
#define L 2 // Storage for filter taps
#define KM 10 // Max number of bands
#define Q 1.2247449 /* Q value for band-pass filters 1.2247=(3/2)^(1/2)
gives 4dB suppression @ Fc*2 and Fc/2 */
// Center frequencies for band-pass filters
/* Center frequencies for band-pass filters
The different frequency bands are:
nr. center frequency
0 31.25 Hz
1 62.50 Hz
2 125.0 Hz
3 250.0 Hz
4 500.0 Hz
5 1.000 kHz
6 2.000 kHz
7 4.000 kHz
8 8.000 kHz
9 16.00 kHz
*/
#define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000}
// Maximum and minimum gain for the bands
@ -41,12 +52,12 @@
// Data for specific instances of this filter
typedef struct af_equalizer_s
{
float a[KM][L]; // A weights
float b[KM][L]; // B weights
float wq[NCH][KM][L]; // Circular buffer for W data
float g[NCH][KM]; // Gain factor for each channel and band
int K; // Number of used eq bands
int channels; // Number of channels
float a[KM][L]; // A weights
float b[KM][L]; // B weights
float wq[AF_NCH][KM][L]; // Circular buffer for W data
float g[AF_NCH][KM]; // Gain factor for each channel and band
int K; // Number of used eq bands
int channels; // Number of channels
} af_equalizer_t;
// 2nd order Band-pass Filter design
@ -76,8 +87,8 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
af->data->rate = ((af_data_t*)arg)->rate;
af->data->nch = ((af_data_t*)arg)->nch;
af->data->format = AF_FORMAT_NE | AF_FORMAT_SI;
af->data->bps = 2;
af->data->format = AF_FORMAT_NE | AF_FORMAT_F;
af->data->bps = 4;
// Calculate number of active filters
s->K=KM;
@ -85,7 +96,8 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
s->K--;
if(s->K != KM)
af_msg(AF_MSG_INFO,"Limiting the number of filters to %i due to low sample rate.\n",s->K);
af_msg(AF_MSG_INFO,"[equalizer] Limiting the number of filters to"
" %i due to low sample rate.\n",s->K);
// Generate filter taps
for(k=0;k<s->K;k++)
@ -94,18 +106,14 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
// Calculate how much this plugin adds to the overall time delay
af->delay += 2000.0/((float)af->data->rate);
// Only signed 16 bit little endian is supported
if(af->data->format != ((af_data_t*)arg)->format ||
af->data->bps != ((af_data_t*)arg)->bps)
return AF_FALSE;
return AF_OK;
return af_test_output(af,arg);
}
case AF_CONTROL_COMMAND_LINE:{
float g[10]={0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
int i,j;
sscanf((char*)arg,"%f:%f:%f:%f:%f:%f:%f:%f:%f:%f", &g[0], &g[1],
&g[2], &g[3], &g[4], &g[5], &g[6], &g[7], &g[8] ,&g[9]);
for(i=0;i<NCH;i++){
for(i=0;i<AF_NCH;i++){
for(j=0;j<KM;j++){
((af_equalizer_t*)af->setup)->g[i][j] =
pow(10.0,clamp(g[j],G_MIN,G_MAX)/20.0)-1.0;
@ -113,23 +121,28 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
}
return AF_OK;
}
case AF_CONTROL_EQUALIZER_SET_GAIN:{
float gain = ((equalizer_t*)arg)->gain;
int ch = ((equalizer_t*)arg)->channel;
int band = ((equalizer_t*)arg)->band;
if(ch > NCH || ch < 0 || band > KM || band < 0)
case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET:{
float* gain = ((af_control_ext_t*)arg)->arg;
int ch = ((af_control_ext_t*)arg)->ch;
int k;
if(ch > AF_NCH || ch < 0)
return AF_ERROR;
s->g[ch][band] = pow(10.0,clamp(gain,G_MIN,G_MAX)/20.0)-1.0;
for(k = 0 ; k<KM ; k++)
s->g[ch][k] = pow(10.0,clamp(gain[k],G_MIN,G_MAX)/20.0)-1.0;
return AF_OK;
}
case AF_CONTROL_EQUALIZER_GET_GAIN:{
int ch =((equalizer_t*)arg)->channel;
int band =((equalizer_t*)arg)->band;
if(ch > NCH || ch < 0 || band > KM || band < 0)
case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_GET:{
float* gain = ((af_control_ext_t*)arg)->arg;
int ch = ((af_control_ext_t*)arg)->ch;
int k;
if(ch > AF_NCH || ch < 0)
return AF_ERROR;
((equalizer_t*)arg)->gain = log10(s->g[ch][band]+1.0) * 20.0;
for(k = 0 ; k<KM ; k++)
gain[k] = log10(s->g[ch][k]+1.0) * 20.0;
return AF_OK;
}
}
@ -155,13 +168,13 @@ static af_data_t* play(struct af_instance_s* af, af_data_t* data)
while(ci--){
float* g = s->g[ci]; // Gain factor
int16_t* in = ((int16_t*)c->audio)+ci;
int16_t* out = ((int16_t*)c->audio)+ci;
int16_t* end = in + c->len/2; // Block loop end
float* in = ((float*)c->audio)+ci;
float* out = ((float*)c->audio)+ci;
float* end = in + c->len/4; // Block loop end
while(in < end){
register uint32_t k = 0; // Frequency band index
register float yt = (float)(*in); // Current input sample
register uint32_t k = 0; // Frequency band index
register float yt = *in; // Current input sample
in+=nch;
// Run the filters
@ -177,7 +190,7 @@ static af_data_t* play(struct af_instance_s* af, af_data_t* data)
wq[0] = w;
}
// Calculate output
*out=(int16_t)(yt/(4.0*10.0));
*out=yt/(4.0*10.0);
out+=nch;
}
}

View File

@ -126,26 +126,32 @@ static char* fmt2str(int format, char* str, size_t size)
return str;
}
// Helper function to check sanity for input arguments
int check_sanity(af_data_t* data)
{
char buf[256];
// Sanity check for bytes per sample
if(data->bps != 4 && data->bps != 2 && data->bps != 1){
af_msg(AF_MSG_ERROR,"[format] The number of bytes per sample must be 1, 2 or 4. Current value is %i \n",data->bps);
return AF_ERROR;
}
// Helper functions to check sanity for input arguments
// Check for unsupported formats
switch(data->format & AF_FORMAT_SPECIAL_MASK){
case(AF_FORMAT_MPEG2):
case(AF_FORMAT_AC3):
af_msg(AF_MSG_ERROR,"[format] Sample format %s not yet supported \n",
fmt2str(data->format,buf,255));
// Sanity check for bytes per sample
int check_bps(int bps)
{
if(bps != 4 && bps != 2 && bps != 1){
af_msg(AF_MSG_ERROR,"[format] The number of bytes per sample"
" must be 1, 2 or 4. Current value is %i \n",bps);
return AF_ERROR;
}
return AF_OK;
}
}
// Check for unsupported formats
int check_format(int format)
{
char buf[256];
switch(format & AF_FORMAT_SPECIAL_MASK){
case(AF_FORMAT_MPEG2):
case(AF_FORMAT_AC3):
af_msg(AF_MSG_ERROR,"[format] Sample format %s not yet supported \n",
fmt2str(format,buf,255));
return AF_ERROR;
}
return AF_OK;
}
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
@ -158,10 +164,12 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
if(af->data->format == ((af_data_t*)arg)->format &&
af->data->bps == ((af_data_t*)arg)->bps)
return AF_DETACH;
// Check for errors in configuraton
if(AF_OK != check_sanity((af_data_t*)arg) ||
AF_OK != check_sanity(af->data))
if((AF_OK != check_bps(((af_data_t*)arg)->bps)) ||
(AF_OK != check_format(((af_data_t*)arg)->format)) ||
(AF_OK != check_bps(af->data->bps)) ||
(AF_OK != check_format(af->data->format)))
return AF_ERROR;
af_msg(AF_MSG_VERBOSE,"[format] Changing sample format from %ibit %sto %ibit %s \n",
@ -175,35 +183,47 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
return AF_OK;
}
case AF_CONTROL_COMMAND_LINE:{
af_data_t d={NULL,0,0,0,0,2};
int bps = 2;
int format = AF_FORMAT_NE;
char str[256];
str[0] = '\0';
sscanf((char*)arg,"%i:%s",&(d.bps),str);
sscanf((char*)arg,"%i:%s",&bps,str);
// Convert string to format
d.format = str2fmt(str);
format = str2fmt(str);
// Automatic correction of errors
switch(d.format & AF_FORMAT_SPECIAL_MASK){
switch(format & AF_FORMAT_SPECIAL_MASK){
case(AF_FORMAT_A_LAW):
case(AF_FORMAT_MU_LAW):
d.bps=1; break;
bps=1; break;
case(AF_FORMAT_AC3):
d.bps=4; break; // I think
bps=4; break; // I think
}
if(AF_FORMAT_F == (d.format & AF_FORMAT_POINT_MASK))
d.bps=4;
return af->control(af,AF_CONTROL_FORMAT,&d);
if(AF_FORMAT_F == (format & AF_FORMAT_POINT_MASK))
bps=4;
if((AF_OK != af->control(af,AF_CONTROL_FORMAT_BPS | AF_CONTROL_SET,&bps)) ||
(AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format)))
return AF_ERROR;
return AF_OK;
}
case AF_CONTROL_FORMAT:
case AF_CONTROL_FORMAT_BPS | AF_CONTROL_SET:
// Reinit must be called after this function has been called
// Check for errors in configuraton
if(AF_OK != check_sanity((af_data_t*)arg))
if(AF_OK != check_bps(*(int*)arg))
return AF_ERROR;
af->data->format = ((af_data_t*)arg)->format;
af->data->bps=((af_data_t*)arg)->bps;
af->data->bps = *(int*)arg;
return AF_OK;
case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET:
// Reinit must be called after this function has been called
// Check for errors in configuraton
if(AF_OK != check_format(*(int*)arg))
return AF_ERROR;
af->data->format = *(int*)arg;
return AF_OK;
}
return AF_UNKNOWN;

157
libaf/af_gate.c Normal file
View File

@ -0,0 +1,157 @@
/*=============================================================================
//
// This software has been released under the terms of the GNU Public
// license. See http://www.gnu.org/copyleft/gpl.html for details.
//
// Copyright 2002 Anders Johansson ajh@atri.curtin.edu.au
//
//=============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include "af.h"
// Data for specific instances of this filter
typedef struct af_gate_s
{
int enable[AF_NCH]; // Enable/disable / channel
float time[AF_NCH]; // Forgetting factor for power estimate
float pow[AF_NCH]; // Estimated power level [dB]
float tresh[AF_NCH]; // Threshold [dB]
float attack[AF_NCH]; // Attack time [ms]
float release[AF_NCH]; // Release time [ms]
float range[AF_NCH]; // Range level [dB]
}af_gate_t;
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
af_gate_t* s = (af_gate_t*)af->setup;
switch(cmd){
case AF_CONTROL_REINIT:
// Sanity check
if(!arg) return AF_ERROR;
af->data->rate = ((af_data_t*)arg)->rate;
af->data->nch = ((af_data_t*)arg)->nch;
af->data->format = AF_FORMAT_F | AF_FORMAT_NE;
af->data->bps = 4;
// Time constant set to 0.1s
// s->alpha = (1.0/0.2)/(2.0*M_PI*(float)((af_data_t*)arg)->rate);
return af_test_output(af,(af_data_t*)arg);
case AF_CONTROL_COMMAND_LINE:{
/* float v=-10.0; */
/* float vol[AF_NCH]; */
/* float s=0.0; */
/* float clipp[AF_NCH]; */
/* int i; */
/* sscanf((char*)arg,"%f:%f", &v, &s); */
/* for(i=0;i<AF_NCH;i++){ */
/* vol[i]=v; */
/* clipp[i]=s; */
/* } */
/* if(AF_OK != control(af,AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET, clipp)) */
/* return AF_ERROR; */
/* return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol); */
}
case AF_CONTROL_GATE_ON_OFF | AF_CONTROL_SET:
memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int));
return AF_OK;
case AF_CONTROL_GATE_ON_OFF | AF_CONTROL_GET:
memcpy((int*)arg,s->enable,AF_NCH*sizeof(int));
return AF_OK;
case AF_CONTROL_GATE_THRESH | AF_CONTROL_SET:
return af_from_dB(AF_NCH,(float*)arg,s->tresh,20.0,-60.0,-1.0);
case AF_CONTROL_GATE_THRESH | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->tresh,(float*)arg,10.0);
case AF_CONTROL_GATE_ATTACK | AF_CONTROL_SET:
return af_from_ms(AF_NCH,(float*)arg,s->attack,af->data->rate,500.0,0.1);
case AF_CONTROL_GATE_ATTACK | AF_CONTROL_GET:
return af_to_ms(AF_NCH,s->attack,(float*)arg,af->data->rate);
case AF_CONTROL_GATE_RELEASE | AF_CONTROL_SET:
return af_from_ms(AF_NCH,(float*)arg,s->release,af->data->rate,3000.0,10.0);
case AF_CONTROL_GATE_RELEASE | AF_CONTROL_GET:
return af_to_ms(AF_NCH,s->release,(float*)arg,af->data->rate);
case AF_CONTROL_GATE_RANGE | AF_CONTROL_SET:
return af_from_dB(AF_NCH,(float*)arg,s->range,20.0,100.0,0.0);
case AF_CONTROL_GATE_RANGE | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->range,(float*)arg,10.0);
}
return AF_UNKNOWN;
}
// Deallocate memory
static void uninit(struct af_instance_s* af)
{
if(af->data)
free(af->data);
if(af->setup)
free(af->setup);
}
// Filter data through filter
static af_data_t* play(struct af_instance_s* af, af_data_t* data)
{
af_data_t* c = data; // Current working data
af_gate_t* s = (af_gate_t*)af->setup; // Setup for this instance
float* a = (float*)c->audio; // Audio data
int len = c->len/4; // Number of samples
int ch = 0; // Channel counter
register int nch = c->nch; // Number of channels
register int i = 0;
// Noise gate
for(ch = 0; ch < nch ; ch++){
if(s->enable[ch]){
float t = 1.0 - s->time[ch];
for(i=ch;i<len;i+=nch){
register float x = a[i];
register float pow = x*x;
s->pow[ch] = t*s->pow[ch] +
pow*s->time[ch]; // LP filter
if(pow < s->pow[ch]){
;
}
else{
;
}
a[i] = x;
}
}
}
return c;
}
// Allocate memory and set function pointers
static int open(af_instance_t* af){
af->control=control;
af->uninit=uninit;
af->play=play;
af->mul.n=1;
af->mul.d=1;
af->data=calloc(1,sizeof(af_data_t));
af->setup=calloc(1,sizeof(af_gate_t));
if(af->data == NULL || af->setup == NULL)
return AF_ERROR;
return AF_OK;
}
// Description of this filter
af_info_t af_info_gate = {
"Noise gate audio filter",
"gate",
"Anders",
"",
AF_FLAGS_NOT_REENTRANT,
open
};

184
libaf/af_pan.c Normal file
View File

@ -0,0 +1,184 @@
/*=============================================================================
//
// This software has been released under the terms of the GNU Public
// license. See http://www.gnu.org/copyleft/gpl.html for details.
//
// Copyright 2002 Anders Johansson ajh@atri.curtin.edu.au
//
//=============================================================================
*/
/* */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include "af.h"
// Data for specific instances of this filter
typedef struct af_pan_s
{
float level[AF_NCH][AF_NCH]; // Gain level for each channel
}af_pan_t;
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
af_pan_t* s = af->setup;
switch(cmd){
case AF_CONTROL_REINIT:
// Sanity check
if(!arg) return AF_ERROR;
af->data->rate = ((af_data_t*)arg)->rate;
af->data->format = AF_FORMAT_F | AF_FORMAT_NE;
af->data->bps = 4;
af->mul.n = af->data->nch;
af->mul.d = ((af_data_t*)arg)->nch;
if((af->data->format != ((af_data_t*)arg)->format) ||
(af->data->bps != ((af_data_t*)arg)->bps)){
((af_data_t*)arg)->format = af->data->format;
((af_data_t*)arg)->bps = af->data->bps;
return AF_FALSE;
}
return control(af,AF_CONTROL_PAN_NOUT | AF_CONTROL_SET, &af->data->nch);
case AF_CONTROL_COMMAND_LINE:{
int nch = 0;
int n = 0;
char* cp = NULL;
int j,k;
// Read number of outputs
sscanf((char*)arg,"%i%n", &nch,&n);
if(AF_OK != control(af,AF_CONTROL_PAN_NOUT | AF_CONTROL_SET, &nch))
return AF_ERROR;
// Read pan values
cp = &((char*)arg)[n];
j = 0; k = 0;
while((*cp == ':') && (k < AF_NCH)){
sscanf(cp, ":%f%n" , &s->level[k][j], &n);
s->level[k][j] = clamp(s->level[k][j],0.0,1.0);
af_msg(AF_MSG_VERBOSE,"[pan] Pan level from channel %i to"
" channel %i = %f\n",j,k,s->level[k][j]);
cp =&cp[n];
j++;
if(j>=nch){
j = 0;
k++;
}
}
return AF_OK;
}
case AF_CONTROL_PAN_LEVEL | AF_CONTROL_SET:{
int i;
int ch = ((af_control_ext_t*)arg)->ch;
float* level = ((af_control_ext_t*)arg)->arg;
for(i=0;i<AF_NCH;i++)
s->level[ch][i] = clamp(level[i],0.0,1.0);
return AF_OK;
}
case AF_CONTROL_PAN_LEVEL | AF_CONTROL_GET:{
int i;
int ch = ((af_control_ext_t*)arg)->ch;
float* level = ((af_control_ext_t*)arg)->arg;
for(i=0;i<AF_NCH;i++)
level[i] = s->level[ch][i];
return AF_OK;
}
case AF_CONTROL_PAN_NOUT | AF_CONTROL_SET:
// Reinit must be called after this function has been called
// Sanity check
if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > 6){
af_msg(AF_MSG_ERROR,"[pan] The number of output channels must be"
" between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
return AF_ERROR;
}
af->data->nch=((int*)arg)[0];
return AF_OK;
case AF_CONTROL_PAN_NOUT | AF_CONTROL_GET:
*(int*)arg = af->data->nch;
return AF_OK;
}
return AF_UNKNOWN;
}
// Deallocate memory
static void uninit(struct af_instance_s* af)
{
if(af->data)
free(af->data);
if(af->setup)
free(af->setup);
}
// Filter data through filter
static af_data_t* play(struct af_instance_s* af, af_data_t* data)
{
af_data_t* c = data; // Current working data
af_data_t* l = af->data; // Local data
af_pan_t* s = af->setup; // Setup for this instance
float* in = c->audio; // Input audio data
float* out = NULL; // Output audio data
float* end = in+c->len/4; // End of loop
int nchi = c->nch; // Number of input channels
int ncho = l->nch; // Number of output channels
register int j,k;
if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
return NULL;
out = l->audio;
// Execute panning
// FIXME: Too slow
while(in < end){
for(j=0;j<ncho;j++){
register float x = 0.0;
register float* tin = in;
for(k=0;k<nchi;k++)
x += tin[k] * s->level[j][k];
out[j] = x;
}
out+= ncho;
in+= nchi;
}
// Set output data
c->audio = l->audio;
c->len = (c->len*af->mul.n)/af->mul.d;
c->nch = l->nch;
return c;
}
// Allocate memory and set function pointers
static int open(af_instance_t* af){
af->control=control;
af->uninit=uninit;
af->play=play;
af->mul.n=1;
af->mul.d=1;
af->data=calloc(1,sizeof(af_data_t));
af->setup=calloc(1,sizeof(af_pan_t));
if(af->data == NULL || af->setup == NULL)
return AF_ERROR;
// Set initial pan to pass-through.
return AF_OK;
}
// Description of this filter
af_info_t af_info_pan = {
"Panning audio filter",
"pan",
"Anders",
"",
AF_FLAGS_NOT_REENTRANT,
open
};

View File

@ -25,45 +25,36 @@
slow and to 16 if the machine is fast and has MMX.
*/
#if !defined(HAVE_SSE) && !defined(HAVE_3DNOW) // This machine is slow
#if !defined(HAVE_MMX) // This machine is slow
#define L8
#else
#define L16
#endif
#define L 8 // Filter length
// Unrolled loop to speed up execution
#define FIR(x,w,y) \
(y[0]) = ( w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3] \
+ w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7] ) >> 16
#else /* Fast machine */
#define L 16
// Unrolled loop to speed up execution
#define FIR(x,w,y) \
y[0] = ( w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] \
+ w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] \
+ w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11] \
+ w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15] ) >> 16
#endif /* Fast machine */
// Macro to add data to circular que
#define ADDQUE(xi,xq,in)\
xq[xi]=xq[xi+L]=(*in);\
xi=(xi-1)&(L-1);
#include "af_resample.h"
// Filtering types
#define TYPE_LIN 0 // Linear interpolation
#define TYPE_INT 1 // 16 bit integer
#define TYPE_FLOAT 2 // 32 bit floating point
// Accuracy for linear interpolation
#define STEPACCURACY 32
// local data
typedef struct af_resample_s
{
int16_t* w; // Current filter weights
int16_t** xq; // Circular buffers
void* w; // Current filter weights
void** xq; // Circular buffers
uint32_t xi; // Index for circular buffers
uint32_t wi; // Index for w
uint32_t i; // Number of new samples to put in x queue
uint32_t i; // Number of new samples to put in x queue
uint32_t dn; // Down sampling factor
uint32_t up; // Up sampling factor
uint64_t step; // Step size for linear interpolation
uint64_t pt; // Pointer remainder for linear interpolation
int sloppy; // Enable sloppy resampling to reduce memory usage
int fast; // Enable linear interpolation instead of filtering
int type; // Filter type
} af_resample_t;
// Euclids algorithm for calculating Greatest Common Divisor GCD(a,b)
@ -82,96 +73,50 @@ static inline int gcd(register int a, register int b)
return b;
}
static int upsample(af_data_t* c,af_data_t* l, af_resample_t* s)
// Fast linear interpolation resample with modest audio quality
static int linint(af_data_t* c,af_data_t* l, af_resample_t* s)
{
uint32_t ci = l->nch; // Index for channels
uint32_t len = 0; // Number of input samples
uint32_t nch = l->nch; // Number of channels
uint32_t inc = s->up/s->dn;
uint32_t level = s->up%s->dn;
uint32_t up = s->up;
uint32_t dn = s->dn;
register int16_t* w = s->w;
register uint32_t wi = 0;
register uint32_t xi = 0;
// Index current channel
while(ci--){
// Temporary pointers
register int16_t* x = s->xq[ci];
register int16_t* in = ((int16_t*)c->audio)+ci;
register int16_t* out = ((int16_t*)l->audio)+ci;
int16_t* end = in+c->len/2; // Block loop end
wi = s->wi; xi = s->xi;
while(in < end){
register uint32_t i = inc;
if(wi<level) i++;
ADDQUE(xi,x,in);
in+=nch;
while(i--){
// Run the FIR filter
FIR((&x[xi]),(&w[wi*L]),out);
len++; out+=nch;
// Update wi to point at the correct polyphase component
wi=(wi+dn)%up;
}
}
}
// Save values that needs to be kept for next time
s->wi = wi;
s->xi = xi;
return len;
}
static int downsample(af_data_t* c,af_data_t* l, af_resample_t* s)
{
uint32_t ci = l->nch; // Index for channels
uint32_t len = 0; // Number of output samples
uint32_t nch = l->nch; // Number of channels
uint32_t inc = s->dn/s->up;
uint32_t level = s->dn%s->up;
uint32_t up = s->up;
uint32_t dn = s->dn;
register int32_t i = 0;
register uint32_t wi = 0;
register uint32_t xi = 0;
uint32_t len = 0; // Number of input samples
uint32_t nch = l->nch; // Words pre transfer
uint64_t step = s->step;
int16_t* in16 = ((int16_t*)c->audio);
int16_t* out16 = ((int16_t*)l->audio);
int32_t* in32 = ((int32_t*)c->audio);
int32_t* out32 = ((int32_t*)l->audio);
uint64_t end = ((((uint64_t)c->len)/2LL)<<STEPACCURACY);
uint64_t pt = s->pt;
uint16_t tmp;
// Index current channel
while(ci--){
// Temporary pointers
register int16_t* x = s->xq[ci];
register int16_t* in = ((int16_t*)c->audio)+ci;
register int16_t* out = ((int16_t*)l->audio)+ci;
register int16_t* end = in+c->len/2; // Block loop end
i = s->i; wi = s->wi; xi = s->xi;
while(in < end){
ADDQUE(xi,x,in);
in+=nch;
if((--i)<=0){
// Run the FIR filter
FIR((&x[xi]),(&s->w[wi*L]),out);
len++; out+=nch;
// Update wi to point at the correct polyphase component
wi=(wi+dn)%up;
// Insert i number of new samples in queue
i = inc;
if(wi<level) i++;
}
switch (nch){
case 1:
while(pt < end){
out16[len++]=in16[pt>>STEPACCURACY];
pt+=step;
}
s->pt=pt & ((1LL<<STEPACCURACY)-1);
break;
case 2:
end/=2;
while(pt < end){
out32[len++]=in32[pt>>STEPACCURACY];
pt+=step;
}
len=(len<<1);
s->pt=pt & ((1LL<<STEPACCURACY)-1);
break;
default:
end /=nch;
while(pt < end){
tmp=nch;
do {
tmp--;
out16[len+tmp]=in16[tmp+(pt>>STEPACCURACY)*nch];
} while (tmp);
len+=nch;
pt+=step;
}
s->pt=pt & ((1LL<<STEPACCURACY)-1);
}
// Save values that needs to be kept for next time
s->wi = wi;
s->xi = xi;
s->i = i;
return len;
}
@ -184,13 +129,24 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
af_data_t* n = (af_data_t*)arg; // New configureation
int i,d = 0;
int rv = AF_OK;
size_t tsz = (s->type==TYPE_INT) ? sizeof(int16_t) : sizeof(float);
// Make sure this filter isn't redundant
if(af->data->rate == n->rate)
return AF_DETACH;
// If linear interpolation
if(s->type == TYPE_LIN){
s->pt=0LL;
s->step=((uint64_t)n->rate<<STEPACCURACY)/(uint64_t)af->data->rate+1LL;
af_msg(AF_MSG_VERBOSE,"[resample] Linear interpolation step: 0x%016X.\n",
s->step);
af->mul.n = af->data->rate;
af->mul.d = n->rate;
}
// Create space for circular bufers (if nesessary)
if(af->data->nch != n->nch){
if((af->data->nch != n->nch) && (s->type != TYPE_LIN)){
// First free the old ones
if(s->xq){
for(i=1;i<af->data->nch;i++)
@ -199,20 +155,30 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
free(s->xq);
}
// ... then create new
s->xq = malloc(n->nch*sizeof(int16_t*));
s->xq = malloc(n->nch*sizeof(void*));
for(i=0;i<n->nch;i++)
s->xq[i] = malloc(2*L*sizeof(int16_t));
s->xq[i] = malloc(2*L*tsz);
s->xi = 0;
}
// Set parameters
af->data->nch = n->nch;
af->data->format = AF_FORMAT_NE | AF_FORMAT_SI;
af->data->bps = 2;
if(s->type == TYPE_INT || s->type == TYPE_LIN){
af->data->format = AF_FORMAT_NE | AF_FORMAT_SI;
af->data->bps = 2;
}
else{
af->data->format = AF_FORMAT_NE | AF_FORMAT_F;
af->data->bps = 4;
}
if(af->data->format != n->format || af->data->bps != n->bps)
rv = AF_FALSE;
n->format = AF_FORMAT_NE | AF_FORMAT_SI;
n->bps = 2;
n->format = af->data->format;
n->bps = af->data->bps;
// If linear interpolation is used the setup is done.
if(s->type == TYPE_LIN)
return rv;
// Calculate up and down sampling factors
d=gcd(af->data->rate,n->rate);
@ -244,7 +210,7 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
w = malloc(sizeof(float) * s->up *L);
if(NULL != s->w)
free(s->w);
s->w = malloc(L*s->up*sizeof(int16_t));
s->w = malloc(L*s->up*tsz);
// Design prototype filter type using Kaiser window with beta = 10
if(NULL == w || NULL == s->w ||
@ -256,13 +222,18 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
wt=w;
for(j=0;j<L;j++){//Columns
for(i=0;i<s->up;i++){//Rows
float t=(float)s->up*32767.0*(*wt);
s->w[i*L+j] = (int16_t)((t>=0.0)?(t+0.5):(t-0.5));
if(s->type == TYPE_INT){
float t=(float)s->up*32767.0*(*wt);
((int16_t*)s->w)[i*L+j] = (int16_t)((t>=0.0)?(t+0.5):(t-0.5));
}
else
((float*)s->w)[i*L+j] = (float)s->up*(*wt);
wt++;
}
}
free(w);
af_msg(AF_MSG_VERBOSE,"[resample] New filter designed up: %i down: %i\n", s->up, s->dn);
af_msg(AF_MSG_VERBOSE,"[resample] New filter designed up: %i "
"down: %i\n", s->up, s->dn);
}
// Set multiplier and delay
@ -274,20 +245,30 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
case AF_CONTROL_COMMAND_LINE:{
af_resample_t* s = (af_resample_t*)af->setup;
int rate=0;
sscanf((char*)arg,"%i:%i:%i",&rate,&(s->sloppy), &(s->fast));
return af->control(af,AF_CONTROL_RESAMPLE,&rate);
int lin=0;
sscanf((char*)arg,"%i:%i:%i", &rate, &(s->sloppy), &lin);
if(lin)
s->type = TYPE_LIN;
return af->control(af,AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET, &rate);
}
case AF_CONTROL_RESAMPLE:
case AF_CONTROL_POST_CREATE:
((af_resample_t*)af->setup)->type =
((af_cfg_t*)arg)->force == AF_INIT_SLOW ? TYPE_INT : TYPE_FLOAT;
return AF_OK;
case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
// Reinit must be called after this function has been called
// Sanity check
if(((int*)arg)[0] < 8000 || ((int*)arg)[0] > 192000){
af_msg(AF_MSG_ERROR,"[resample] The output sample frequency must be between 8kHz and 192kHz. Current value is %i \n",((int*)arg)[0]);
af_msg(AF_MSG_ERROR,"[resample] The output sample frequency "
"must be between 8kHz and 192kHz. Current value is %i \n",
((int*)arg)[0]);
return AF_ERROR;
}
af->data->rate=((int*)arg)[0];
af_msg(AF_MSG_VERBOSE,"[resample] Changing sample rate to %iHz\n",af->data->rate);
af_msg(AF_MSG_VERBOSE,"[resample] Changing sample rate "
"to %iHz\n",af->data->rate);
return AF_OK;
}
return AF_UNKNOWN;
@ -312,14 +293,42 @@ static af_data_t* play(struct af_instance_s* af, af_data_t* data)
return NULL;
// Run resampling
if(s->up>s->dn)
len = upsample(c,l,s);
else
len = downsample(c,l,s);
switch(s->type){
case(TYPE_INT):
# define FORMAT_I 1
if(s->up>s->dn){
# define UP
# include "af_resample.h"
# undef UP
}
else{
# define DN
# include "af_resample.h"
# undef DN
}
break;
case(TYPE_FLOAT):
# undef FORMAT_I
# define FORMAT_F 1
if(s->up>s->dn){
# define UP
# include "af_resample.h"
# undef UP
}
else{
# define DN
# include "af_resample.h"
# undef DN
}
break;
case(TYPE_LIN):
len = linint(c, l, s);
break;
}
// Set output data
c->audio = l->audio;
c->len = len*2;
c->len = len*l->bps;
c->rate = l->rate;
return c;

161
libaf/af_resample.h Normal file
View File

@ -0,0 +1,161 @@
/*=============================================================================
//
// This software has been released under the terms of the GNU Public
// license. See http://www.gnu.org/copyleft/gpl.html for details.
//
// Copyright 2002 Anders Johansson ajh@atri.curtin.edu.au
//
//=============================================================================
*/
/* This file contains the resampling engine, the sample format is
controlled by the FORMAT parameter, the filter length by the L
parameter and the resampling type by UP and DN. This file should
only be included by af_resample.c
*/
#undef L
#undef SHIFT
#undef FORMAT
#undef FIR
#undef ADDQUE
/* The lenght Lxx definition selects the length of each poly phase
component. Valid definitions are L8 and L16 where the number
defines the nuber of taps. This definition affects the
computational complexity, the performance and the memory usage.
*/
/* The FORMAT_x parameter selects the sample format type currently
float and int16 are supported. Thes two formats are selected by
defining eiter FORMAT_F or FORMAT_I. The advantage of using float
is that the amplitude and therefore the SNR isn't affected by the
filtering, the disadvantage is that it is a lot slower.
*/
#if defined(FORMAT_I)
#define SHIFT >>16
#define FORMAT int16_t
#else
#define SHIFT
#define FORMAT float
#endif
// Short filter
#if defined(L8)
#define L 8 // Filter length
// Unrolled loop to speed up execution
#define FIR(x,w,y) \
(y[0]) = ( w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3] \
+ w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7] ) SHIFT
#else /* L8/L16 */
#define L 16
// Unrolled loop to speed up execution
#define FIR(x,w,y) \
y[0] = ( w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] \
+ w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] \
+ w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11] \
+ w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15] ) SHIFT
#endif /* L8/L16 */
// Macro to add data to circular que
#define ADDQUE(xi,xq,in)\
xq[xi]=xq[xi+L]=(*in);\
xi=(xi-1)&(L-1);
#if defined(UP)
uint32_t ci = l->nch; // Index for channels
uint32_t nch = l->nch; // Number of channels
uint32_t inc = s->up/s->dn;
uint32_t level = s->up%s->dn;
uint32_t up = s->up;
uint32_t dn = s->dn;
uint32_t ns = c->len/l->bps;
register FORMAT* w = s->w;
register uint32_t wi = 0;
register uint32_t xi = 0;
// Index current channel
while(ci--){
// Temporary pointers
register FORMAT* x = s->xq[ci];
register FORMAT* in = ((FORMAT*)c->audio)+ci;
register FORMAT* out = ((FORMAT*)l->audio)+ci;
FORMAT* end = in+ns; // Block loop end
wi = s->wi; xi = s->xi;
while(in < end){
register uint32_t i = inc;
if(wi<level) i++;
ADDQUE(xi,x,in);
in+=nch;
while(i--){
// Run the FIR filter
FIR((&x[xi]),(&w[wi*L]),out);
len++; out+=nch;
// Update wi to point at the correct polyphase component
wi=(wi+dn)%up;
}
}
}
// Save values that needs to be kept for next time
s->wi = wi;
s->xi = xi;
#endif /* UP */
#if defined(DN) /* DN */
uint32_t ci = l->nch; // Index for channels
uint32_t nch = l->nch; // Number of channels
uint32_t inc = s->dn/s->up;
uint32_t level = s->dn%s->up;
uint32_t up = s->up;
uint32_t dn = s->dn;
uint32_t ns = c->len/l->bps;
FORMAT* w = s->w;
register int32_t i = 0;
register uint32_t wi = 0;
register uint32_t xi = 0;
// Index current channel
while(ci--){
// Temporary pointers
register FORMAT* x = s->xq[ci];
register FORMAT* in = ((FORMAT*)c->audio)+ci;
register FORMAT* out = ((FORMAT*)l->audio)+ci;
register FORMAT* end = in+ns; // Block loop end
i = s->i; wi = s->wi; xi = s->xi;
while(in < end){
ADDQUE(xi,x,in);
in+=nch;
if((--i)<=0){
// Run the FIR filter
FIR((&x[xi]),(&w[wi*L]),out);
len++; out+=nch;
// Update wi to point at the correct polyphase component
wi=(wi+dn)%up;
// Insert i number of new samples in queue
i = inc;
if(wi<level) i++;
}
}
}
// Save values that needs to be kept for next time
s->wi = wi;
s->xi = xi;
s->i = i;
#endif /* DN */

79
libaf/af_tools.c Normal file
View File

@ -0,0 +1,79 @@
#include <math.h>
#include <af.h>
/* Convert to gain value from dB. Returns AF_OK if of and AF_ERROR if
fail */
inline int af_from_dB(int n, float* in, float* out, float k, float mi, float ma)
{
int i = 0;
// Sanity check
if(!in || !out)
return AF_ERROR;
for(i=0;i<n;i++){
if(in[i]<=-200)
out[i]=0.0;
else
out[i]=pow(10.0,clamp(in[i],mi,ma)/k);
}
return AF_OK;
}
/* Convert from gain value to dB. Returns AF_OK if of and AF_ERROR if
fail */
inline int af_to_dB(int n, float* in, float* out, float k)
{
int i = 0;
// Sanity check
if(!in || !out)
return AF_ERROR;
for(i=0;i<AF_NCH;i++){
if(in[i] == 0.0)
out[i]=-200.0;
else
out[i]=k*log10(in[i]);
}
return AF_OK;
}
/* Convert from ms to sample time*/
inline int af_from_ms(int n, float* in, float* out, int rate, float mi, float ma)
{
int i = 0;
// Sanity check
if(!in || !out)
return AF_ERROR;
for(i=0;i<AF_NCH;i++)
out[i]=clamp(in[i],ma,mi);
return AF_OK;
}
/* Convert from sample time to ms */
inline int af_to_ms(int n, float* in, float* out, int rate)
{
int i = 0;
// Sanity check
if(!in || !out)
return AF_ERROR;
for(i=0;i<AF_NCH;i++)
out[i]=in[i];
return AF_OK;
}
/* Helper function for testing the output format */
inline int af_test_output(struct af_instance_s* af, af_data_t* out)
{
if((af->data->format != out->format) ||
(af->data->bps != out->bps) ||
(af->data->rate != out->rate) ||
(af->data->nch != out->nch)){
memcpy(out,af->data,sizeof(af_data_t));
return AF_FALSE;
}
return AF_OK;
}

View File

@ -1,19 +1,27 @@
/* This audio filter changes the volume of the sound, and can be used
when the mixer doesn't support the PCM channel. It can handel
between 1 and 6 channels. The volume can be adjusted between -60dB
to +20dB and is set on a per channels basis. The volume can be
written ad read by AF_CONTROL_VOLUME_SET and AF_CONTROL_VOLUME_GET
respectivly.
/*=============================================================================
//
// This software has been released under the terms of the GNU Public
// license. See http://www.gnu.org/copyleft/gpl.html for details.
//
// Copyright 2002 Anders Johansson ajh@atri.curtin.edu.au
//
//=============================================================================
*/
The plugin has support for softclipping, it is enabled by
/* This audio filter changes the volume of the sound, and can be used
when the mixer doesn't support the PCM channel. It can handle
between 1 and 6 channels. The volume can be adjusted between -60dB
to +20dB and is set on a per channels basis. The is accessed through
AF_CONTROL_VOLUME_LEVEL.
The filter has support for soft-clipping, it is enabled by
AF_CONTROL_VOLUME_SOFTCLIPP. It has also a probing feature which
can be used to measure the power in the audio stream, both an
instantanious value and the maximum value can be probed. The
instantaneous value and the maximum value can be probed. The
probing is enable by AF_CONTROL_VOLUME_PROBE_ON_OFF and is done on a
per channel basis. The result from the probing is obtained using
AF_CONTROL_VOLUME_PROBE_GET and AF_CONTROL_VOLUME_PROBE_GET_MAX. The
probed values are calculated in dB. The control of the volume can
be turned off by the AF_CONTROL_VOLUME_ON_OFF switch.
probed values are calculated in dB.
*/
#include <stdio.h>
@ -22,66 +30,22 @@
#include <unistd.h>
#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include "af.h"
// Some limits
#define NCH AF_NCH // Number of channels
#define MIN_S16 -32650
#define MAX_S16 32650
#define MAX_VOL +40.0
#define MIN_VOL -200.0
// Data for specific instances of this filter
typedef struct af_volume_s
{
float volume[NCH]; // Volume for each channel
float power[NCH]; // Instantaneous power in each channel
float maxpower[NCH]; // Maximum power in each channel
float alpha; // Forgetting factor for power estimate
int softclip; // Soft clippng on/off
int probe; // Probing on/off
int onoff; // Volume control on/off
int enable[AF_NCH]; // Enable/disable / channel
float pow[AF_NCH]; // Estimated power level [dB]
float max[AF_NCH]; // Max Power level [dB]
float level[AF_NCH]; // Gain level for each channel
float time; // Forgetting factor for power estimate
int soft; // Enable/disable soft clipping
int fast; // Use fix-point volume control
}af_volume_t;
/* Convert to gain value from dB. Returns AF_OK if of and AF_ERROR if
fail */
inline int from_dB(float* in, float* out, float k)
{
int i = 0;
// Sanity check
if(!in || !out)
return AF_ERROR;
for(i=0;i<NCH;i++){
if(in[i]<MIN_VOL)
out[i]=0.0;
else
out[i]=pow(10.0,clamp(in[i],MIN_VOL,MAX_VOL)/k);
}
return AF_OK;
}
/* Convert from gain value to dB. Returns AF_OK if of and AF_ERROR if
fail */
inline int to_dB(float* in, float* out, float k)
{
int i = 0;
// Sanity check
if(!in || !out)
return AF_ERROR;
for(i=0;i<NCH;i++){
if(in[i] == 0.0)
out[i]=MIN_VOL;
else
out[i]=k*log10(clamp(in[i],MIN_VOL,MAX_VOL));
}
return AF_OK;
}
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
@ -94,48 +58,57 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
af->data->rate = ((af_data_t*)arg)->rate;
af->data->nch = ((af_data_t*)arg)->nch;
af->data->format = AF_FORMAT_SI | AF_FORMAT_LE;
af->data->bps = 2;
// Time constant set to 0.1s
s->alpha = (1.0/0.2)/(2.0*M_PI*(float)((af_data_t*)arg)->rate);
// Only AFMT_S16_LE is supported for now
if(af->data->format != ((af_data_t*)arg)->format ||
af->data->bps != ((af_data_t*)arg)->bps)
return AF_FALSE;
return AF_OK;
if(s->fast){
af->data->format = AF_FORMAT_SI | AF_FORMAT_NE;
af->data->bps = 2;
}
else{
// Cutoff set to 10Hz for forgetting factor
float x = 2.0*M_PI*15.0/(float)af->data->rate;
float t = 2.0-cos(x);
s->time = 1.0 - (t - sqrt(t*t - 1));
af_msg(AF_MSG_DEBUG0,"[volume] Forgetting factor = %0.5f\n",s->time);
af->data->format = AF_FORMAT_F | AF_FORMAT_NE;
af->data->bps = 4;
}
return af_test_output(af,(af_data_t*)arg);
case AF_CONTROL_COMMAND_LINE:{
float v=-10.0;
float vol[6];
int i;
sscanf((char*)arg,"%f:%i:%i:%i", &v,
&(s->softclip), &(s->probe), &(s->onoff));
for(i=0;i<NCH;i++) vol[i]=v;
return from_dB(vol,s->volume,20.0);
float vol[AF_NCH];
int i;
sscanf((char*)arg,"%f:%i", &v, &s->soft);
for(i=0;i<AF_NCH;i++) vol[i]=v;
return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol);
}
case AF_CONTROL_VOLUME_SET:
return from_dB((float*)arg,s->volume,20.0);
case AF_CONTROL_VOLUME_GET:
return to_dB(s->volume,(float*)arg,20.0);
case AF_CONTROL_VOLUME_PROBE_GET:
return to_dB(s->power,(float*)arg,10.0);
case AF_CONTROL_VOLUME_PROBE_GET_MAX:
return to_dB(s->maxpower,(float*)arg,10.0);
case AF_CONTROL_VOLUME_SOFTCLIP:
s->softclip = (int)arg;
return AF_OK;
case AF_CONTROL_VOLUME_PROBE_ON_OFF:
s->probe = (int)arg;
return AF_OK;
case AF_CONTROL_VOLUME_ON_OFF:
s->onoff = (int)arg;
case AF_CONTROL_POST_CREATE:
s->fast = ((af_cfg_t*)arg)->force == AF_INIT_SLOW ? 1 : 0;
return AF_OK;
case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_SET:
memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int));
return AF_OK;
case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_GET:
memcpy((int*)arg,s->enable,AF_NCH*sizeof(int));
return AF_OK;
case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET:
s->soft = *(int*)arg;
return AF_OK;
case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_GET:
*(int*)arg = s->soft;
return AF_OK;
case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET:
return af_from_dB(AF_NCH,(float*)arg,s->level,20.0,-200.0,60.0);
case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->level,(float*)arg,20.0);
case AF_CONTROL_VOLUME_PROBE | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->pow,(float*)arg,10.0);
case AF_CONTROL_VOLUME_PROBE_MAX | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->max,(float*)arg,10.0);
case AF_CONTROL_PRE_DESTROY:{
float m = 0.0;
int i;
for(i=0;i<NCH;i++)
m=max(m,s->maxpower[i]);
for(i=0;i<AF_NCH;i++)
m=max(m,s->max[i]);
af_msg(AF_MSG_INFO,"The maximum volume was %0.2fdB \n",10*log10(m));
return AF_OK;
}
@ -155,57 +128,66 @@ static void uninit(struct af_instance_s* af)
// Filter data through filter
static af_data_t* play(struct af_instance_s* af, af_data_t* data)
{
af_data_t* c = data; // Current working data
af_volume_t* s = (af_volume_t*)af->setup; // Setup for this instance
int16_t* a = (int16_t*)c->audio; // Audio data
int len = c->len/2; // Number of samples
int ch = 0; // Channel counter
register int nch = c->nch; // Number of channels
register int i = 0;
// Probe the data stream
if(s->probe){
for(ch = 0; ch < nch ; ch++){
float alpha = s->alpha;
float beta = 1 - alpha;
float pow = s->power[ch];
float maxpow = s->maxpower[ch];
register float t = 0;
for(i=ch;i<len;i+=nch){
t = ((float)a[i])/32768.0;
t *= t;
// Check maximum power value
if(t>maxpow)
maxpow=t;
// Power estimate made using first order AR model
if(t>pow)
pow=t;
else
pow = beta*pow+alpha*t;
}
s->power[ch] = pow;
s->maxpower[ch] = maxpow;
}
}
af_data_t* c = data; // Current working data
af_volume_t* s = (af_volume_t*)af->setup; // Setup for this instance
int ch = 0; // Channel counter
register int nch = c->nch; // Number of channels
register int i = 0;
// Change the volume.
if(s->onoff){
register int sc = s->softclip;
// Basic operation volume control only (used on slow machines)
if(af->data->format == (AF_FORMAT_SI | AF_FORMAT_NE)){
int16_t* a = (int16_t*)c->audio; // Audio data
int len = c->len/2; // Number of samples
for(ch = 0; ch < nch ; ch++){
register int vol = (int)(255.0 * s->volume[ch]);
for(i=ch;i<len;i+=nch){
register int x;
x=(a[i] * vol) >> 8;
if(sc){
int64_t t=x*x;
t=(t*x) >> 30;
x = (3*x - (int)t) >> 1;
if(s->enable[ch]){
register int vol = (int)(255.0 * s->level[ch]);
for(i=ch;i<len;i+=nch){
register int x = (a[i] * vol) >> 8;
a[i]=clamp(x,SHRT_MIN,SHRT_MAX);
}
}
}
}
// Machine is fast and data is floating point
else if(af->data->format == (AF_FORMAT_F | AF_FORMAT_NE)){
float* a = (float*)c->audio; // Audio data
int len = c->len/4; // Number of samples
for(ch = 0; ch < nch ; ch++){
// Volume control (fader)
if(s->enable[ch]){
float t = 1.0 - s->time;
for(i=ch;i<len;i+=nch){
register float x = a[i];
register float pow = x*x;
// Check maximum power value
if(pow > s->max[ch])
s->max[ch] = pow;
// Set volume
x *= s->level[ch];
// Peak meter
pow = x*x;
if(pow > s->pow[ch])
s->pow[ch] = pow;
else
s->pow[ch] = t*s->pow[ch] + pow*s->time; // LP filter
/* Soft clipping, the sound of a dream, thanks to Jon Wattes
post to Musicdsp.org */
if(s->soft){
if (x >= M_PI/2)
x = 1.0;
else if(x <= -M_PI/2)
x = -1.0;
else
x = sin(x);
}
// Hard clipping
else
x=clamp(x,-1.0,1.0);
a[i] = x;
}
a[i]=clamp(x,MIN_S16,MAX_S16);
}
}
}
return c;
}
@ -222,13 +204,13 @@ static int open(af_instance_t* af){
if(af->data == NULL || af->setup == NULL)
return AF_ERROR;
/* Enable volume control and set initial volume to 0.1 this is a
safety mesure to ensure that the user doesn't blow his
safety measure to ensure that the user doesn't blow his
speakers. If the user isn't happy with this he can use the
commandline parameters to set the initial volume */
((af_volume_t*)af->setup)->onoff = 1;
for(i=0;i<NCH;i++)
((af_volume_t*)af->setup)->volume[i]=0.1;
command-line parameters to set the initial volume */
for(i=0;i<AF_NCH;i++){
((af_volume_t*)af->setup)->enable[i] = 1;
((af_volume_t*)af->setup)->level[i] = 0.1;
}
return AF_OK;
}

View File

@ -1,6 +1,57 @@
#ifndef __af_control_h
#define __af_control_h
/*********************************************
// Control info struct.
//
// This struct is the argument in a info call to a filter.
*/
// Argument types
#define AF_CONTROL_TYPE_BOOL (0x0<<0)
#define AF_CONTROL_TYPE_CHAR (0x1<<0)
#define AF_CONTROL_TYPE_INT (0x2<<0)
#define AF_CONTROL_TYPE_FLOAT (0x3<<0)
#define AF_CONTROL_TYPE_STRUCT (0x4<<0)
#define AF_CONTROL_TYPE_SPECIAL (0x5<<0) // a pointer to a function for example
#define AF_CONTROL_TYPE_MASK (0x7<<0)
// Argument geometry
#define AF_CONTROL_GEOM_SCALAR (0x0<<3)
#define AF_CONTROL_GEOM_ARRAY (0x1<<3)
#define AF_CONTROL_GEOM_MATRIX (0x2<<3)
#define AF_CONTROL_GEOM_MASK (0x3<<3)
// Argument properties
#define AF_CONTROL_PROP_READ (0x0<<5) // The argument can be read
#define AF_CONTROL_PROP_WRITE (0x1<<5) // The argument can be written
#define AF_CONTROL_PROP_SAVE (0x2<<5) // Can be saved
#define AF_CONTROL_PROP_RUNTIME (0x4<<5) // Acessable during execution
#define AF_CONTROL_PROP_CHANNEL (0x8<<5) // Argument is set per channel
#define AF_CONTROL_PROP_MASK (0xF<<5)
typedef struct af_control_info_s{
int def; // Control enumrification
char* name; // Name of argument
char* info; // Description of what it does
int flags; // Flags as defined above
float max; // Max and min value
float min; // (only aplicable on float and int)
int xdim; // 1st dimension
int ydim; // 2nd dimension (=0 for everything except matrix)
size_t sz; // Size of argument in bytes
int ch; // Channel number (for future use)
void* arg; // Data (for future use)
}af_control_info_t;
/*********************************************
// Extended control used with arguments that operates on only one
// channel at the time
*/
typedef struct af_control_ext_s{
void* arg; // Argument
int ch; // Chanel number
}af_control_ext_t;
/*********************************************
// Control parameters
*/
@ -11,9 +62,9 @@
filter specific calls - applies only to some filters
*/
#define AF_CONTROL_MANDATORY_BASE 0
#define AF_CONTROL_OPTIONAL_BASE 100
#define AF_CONTROL_FILTER_SPECIFIC_BASE 200
#define AF_CONTROL_MANDATORY 0x10000000
#define AF_CONTROL_OPTIONAL 0x20000000
#define AF_CONTROL_FILTER_SPECIFIC 0x40000000
// MANDATORY CALLS
@ -23,66 +74,136 @@
should be returned. If the incoming and outgoing data streams are
identical the filter can return AF_DETACH. This will remove the
filter. */
#define AF_CONTROL_REINIT 01 + AF_CONTROL_MANDATORY_BASE
#define AF_CONTROL_REINIT 0x00000100 | AF_CONTROL_MANDATORY
// OPTIONAL CALLS
/* Called just after creation with the af_cfg for the stream in which
the filter resides as input parameter this call can be used by the
filter to initialize itself */
#define AF_CONTROL_POST_CREATE 1 + AF_CONTROL_OPTIONAL_BASE
#define AF_CONTROL_POST_CREATE 0x00000100 | AF_CONTROL_OPTIONAL
// Called just before destruction of a filter
#define AF_CONTROL_PRE_DESTROY 2 + AF_CONTROL_OPTIONAL_BASE
#define AF_CONTROL_PRE_DESTROY 0x00000200 | AF_CONTROL_OPTIONAL
/* Commandline parameters. If there were any commandline parameters
for this specific filter, they will be given as a char* in the
argument */
#define AF_CONTROL_COMMAND_LINE 3 + AF_CONTROL_OPTIONAL_BASE
#define AF_CONTROL_COMMAND_LINE 0x00000300 | AF_CONTROL_OPTIONAL
// FILTER SPECIFIC CALLS
// Set output rate in resample
#define AF_CONTROL_RESAMPLE 1 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Basic operations: These can be ored with any of the below calls
// Set argument
#define AF_CONTROL_SET 0x00000000
// Get argument
#define AF_CONTROL_GET 0x00000001
// Get info about the control, i.e fill in everything except argument
#define AF_CONTROL_INFO 0x00000002
// Set output format in format
#define AF_CONTROL_FORMAT 2 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Resample
// Set output rate in resample
#define AF_CONTROL_RESAMPLE_RATE 0x00000100 | AF_CONTROL_FILTER_SPECIFIC
// Enable sloppy resampling
#define AF_CONTROL_RESAMPLE_SLOPPY 0x00000200 | AF_CONTROL_FILTER_SPECIFIC
// Set resampling accuracy
#define AF_CONTROL_RESAMPLE_ACCURACY 0x00000300 | AF_CONTROL_FILTER_SPECIFIC
// Format
// Set output format bits per sample
#define AF_CONTROL_FORMAT_BPS 0x00000400 | AF_CONTROL_FILTER_SPECIFIC
// Set output format sample format
#define AF_CONTROL_FORMAT_FMT 0x00000500 | AF_CONTROL_FILTER_SPECIFIC
// Channels
// Set number of output channels in channels
#define AF_CONTROL_CHANNELS 3 + AF_CONTROL_FILTER_SPECIFIC_BASE
#define AF_CONTROL_CHANNELS 0x00000600 | AF_CONTROL_FILTER_SPECIFIC
// Set delay length in delay
#define AF_CONTROL_DELAY_SET_LEN 4 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Set number of channel routes
#define AF_CONTROL_CHANNELS_ROUTES 0x00000700 | AF_CONTROL_FILTER_SPECIFIC
// Set channel routing pair, arg is int[2] and ch is used
#define AF_CONTROL_CHANNELS_ROUTING 0x00000800 | AF_CONTROL_FILTER_SPECIFIC
// Set nuber of channel routing pairs, arg is int*
#define AF_CONTROL_CHANNELS_NR 0x00000900 | AF_CONTROL_FILTER_SPECIFIC
// Set make af_channels into a router
#define AF_CONTROL_CHANNELS_ROUTER 0x00000A00 | AF_CONTROL_FILTER_SPECIFIC
// Volume
// Set volume level, arg is a float* with the volume for all the channels
#define AF_CONTROL_VOLUME_SET 5 + AF_CONTROL_FILTER_SPECIFIC_BASE
/* Get volume level for all channels, arg is a float* that will
contain the volume for all the channels */
#define AF_CONTROL_VOLUME_GET 6 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Turn volume control on and off, arg is binary
#define AF_CONTROL_VOLUME_ON_OFF 7 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Turn volume control on and off, arg is int*
#define AF_CONTROL_VOLUME_ON_OFF 0x00000B00 | AF_CONTROL_FILTER_SPECIFIC
// Turn soft clipping of the volume on and off, arg is binary
#define AF_CONTROL_VOLUME_SOFTCLIP 8 + AF_CONTROL_FILTER_SPECIFIC_BASE
#define AF_CONTROL_VOLUME_SOFTCLIP 0x00000C00 | AF_CONTROL_FILTER_SPECIFIC
// Get the probed power level for all channels, arg is a float*
#define AF_CONTROL_VOLUME_PROBE_GET 9 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Set volume level, arg is a float* with the volume for all the channels
#define AF_CONTROL_VOLUME_LEVEL 0x00000D00 | AF_CONTROL_FILTER_SPECIFIC
// Get the maximum probed power level for all channels, arg is a float*
#define AF_CONTROL_VOLUME_PROBE_GET_MAX 10 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Probed power level for all channels, arg is a float*
#define AF_CONTROL_VOLUME_PROBE 0x00000E00 | AF_CONTROL_FILTER_SPECIFIC
// Turn probing on and off, arg is binary
#define AF_CONTROL_VOLUME_PROBE_ON_OFF 11 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Maximum probed power level for all channels, arg is a float*
#define AF_CONTROL_VOLUME_PROBE_MAX 0x00000F00 | AF_CONTROL_FILTER_SPECIFIC
// Set equalizer gain, arg is an equalizer_t*
#define AF_CONTROL_EQUALIZER_SET_GAIN 12 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Compressor/expander
// Turn compressor/expander on and off
#define AF_CONTROL_COMP_ON_OFF 0x00001000 | AF_CONTROL_FILTER_SPECIFIC
// Compression/expansion threshold [dB]
#define AF_CONTROL_COMP_THRESH 0x00001100 | AF_CONTROL_FILTER_SPECIFIC
// Compression/expansion attack time [ms]
#define AF_CONTROL_COMP_ATTACK 0x00001200 | AF_CONTROL_FILTER_SPECIFIC
// Compression/expansion release time [ms]
#define AF_CONTROL_COMP_RELEASE 0x00001300 | AF_CONTROL_FILTER_SPECIFIC
// Compression/expansion gain level [dB]
#define AF_CONTROL_COMP_RATIO 0x00001400 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate
// Turn noise gate on an off
#define AF_CONTROL_GATE_ON_OFF 0x00001500 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate threshold [dB]
#define AF_CONTROL_GATE_THRESH 0x00001600 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate attack time [ms]
#define AF_CONTROL_GATE_ATTACK 0x00001700 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate release time [ms]
#define AF_CONTROL_GATE_RELEASE 0x00001800 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate release range level [dB]
#define AF_CONTROL_GATE_RANGE 0x00001900 | AF_CONTROL_FILTER_SPECIFIC
// Pan
// Pan levels, arg is a control_ext with a float*
#define AF_CONTROL_PAN_LEVEL 0x00001A00 | AF_CONTROL_FILTER_SPECIFIC
// Number of outputs from pan, arg is int*
#define AF_CONTROL_PAN_NOUT 0x00001B00 | AF_CONTROL_FILTER_SPECIFIC
// Set equalizer gain, arg is a control_ext with a float*
#define AF_CONTROL_EQUALIZER_GAIN 0x00001C00 | AF_CONTROL_FILTER_SPECIFIC
// Set delay length in seconds
#define AF_CONTROL_DELAY_LEN 0x00001D00 | AF_CONTROL_FILTER_SPECIFIC
// Get equalizer gain, arg is an equalizer_t*
#define AF_CONTROL_EQUALIZER_GET_GAIN 13 + AF_CONTROL_FILTER_SPECIFIC_BASE
#endif /*__af_control_h */