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:
parent
0e9c0e8aa2
commit
6adaa78ee9
@ -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)
|
||||
|
||||
|
60
libaf/af.c
60
libaf/af.c
@ -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;
|
||||
|
13
libaf/af.h
13
libaf/af.h
@ -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. */
|
||||
|
@ -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
161
libaf/af_comp.c
Normal 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
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
157
libaf/af_gate.c
Normal 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
184
libaf/af_pan.c
Normal 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
|
||||
};
|
@ -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
161
libaf/af_resample.h
Normal 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
79
libaf/af_tools.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
189
libaf/control.h
189
libaf/control.h
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user