1
mirror of https://github.com/mpv-player/mpv synced 2024-10-22 08:51:57 +02:00

Adding new audio output filter layer libaf

git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@7569 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
anders 2002-10-01 06:45:08 +00:00
parent c0091278d8
commit 1f6c494641
15 changed files with 2234 additions and 3 deletions

View File

@ -45,13 +45,13 @@ AO_LIBS = libao2/libao2.a
A_LIBS = $(ALSA_LIB) $(ARTS_LIB) $(NAS_LIB) $(MAD_LIB) $(VORBIS_LIB) $(FAAD_LIB) $(SGIAUDIO_LIB)
CODEC_LIBS = libmpcodecs/libmpcodecs.a mp3lib/libMP3.a liba52/liba52.a libmpeg2/libmpeg2.a $(AV_LIB) $(FAME_LIB)
COMMON_LIBS = $(CODEC_LIBS) libmpdemux/libmpdemux.a input/libinput.a postproc/libpostproc.a linux/libosdep.a $(LIB_LOADER) $(FREETYPE_LIB) $(A_LIBS) $(CSS_LIB) $(XVID_LIB) $(DECORE_LIB) $(TERMCAP_LIB) $(STREAMING_LIB) $(Z_LIB) $(GTK_LIBS) $(PNG_LIB) $(JPEG_LIB) $(GIF_LIB) $(CDPARANOIA_LIB) $(ARCH_LIB) -lm
COMMON_LIBS = $(CODEC_LIBS) libmpdemux/libmpdemux.a input/libinput.a postproc/libpostproc.a linux/libosdep.a $(LIB_LOADER) $(FREETYPE_LIB) $(A_LIBS) $(CSS_LIB) $(XVID_LIB) $(DECORE_LIB) $(TERMCAP_LIB) $(STREAMING_LIB) $(Z_LIB) $(GTK_LIBS) $(PNG_LIB) $(JPEG_LIB) $(GIF_LIB) $(CDPARANOIA_LIB) $(ARCH_LIB) -lm -Llibaf -laf
ifeq ($(VIDIX),yes)
MISC_LIBS += -Llibdha -ldha vidix/libvidix.a
endif
CFLAGS = $(OPTFLAGS) -Ilibmpdemux -Iloader $(VO_INC) $(EXTRA_INC) $(CDPARANOIA_INC) $(FREETYPE_INC) $(SDL_INC) # -Wall
PARTS = libmpdemux libmpcodecs mp3lib liba52 libmpeg2 libavcodec libao2 drivers linux postproc input libvo
PARTS = libmpdemux libmpcodecs mp3lib liba52 libmpeg2 libavcodec libao2 drivers linux postproc input libvo libaf
ifeq ($(VIDIX),yes)
PARTS += libdha vidix
endif
@ -84,7 +84,7 @@ ifeq ($(CSS_USE),yes)
ALL_PRG += $(PRG_FIBMAP)
endif
COMMON_DEPS = $(LOADER_DEP) $(MP1E_DEP) $(AV_DEP) libmpdemux/libmpdemux.a libmpcodecs/libmpcodecs.a libao2/libao2.a liba52/liba52.a mp3lib/libMP3.a libmpeg2/libmpeg2.a linux/libosdep.a postproc/libpostproc.a input/libinput.a libvo/libvo.a
COMMON_DEPS = $(LOADER_DEP) $(MP1E_DEP) $(AV_DEP) libmpdemux/libmpdemux.a libmpcodecs/libmpcodecs.a libao2/libao2.a liba52/liba52.a mp3lib/libMP3.a libmpeg2/libmpeg2.a linux/libosdep.a postproc/libpostproc.a input/libinput.a libvo/libvo.a libaf/libaf.a
ifeq ($(VIDIX),yes)
COMMON_DEPS += libdha/libdha.so vidix/libvidix.a
@ -115,6 +115,9 @@ all: $(ALL_PRG)
.c.o:
$(CC) -c $(CFLAGS) -o $@ $<
libaf/libaf.a:
$(MAKE) -C libaf
libmpdvdkit2/libmpdvdkit.a:
$(MAKE) -C libmpdvdkit2

38
libaf/Makefile Normal file
View File

@ -0,0 +1,38 @@
include ../config.mak
LIBNAME = libaf.a
SRCS=af.c af_dummy.c af_delay.c af_channels.c af_format.c af_resample.c window.c filter.c
OBJS=$(SRCS:.c=.o)
CFLAGS = $(OPTFLAGS) -I. -Wall
.SUFFIXES: .c .o
.c.o:
$(CC) -c $(CFLAGS) -o $@ $<
$(LIBNAME): $(OBJS) Makefile
$(AR) r $(LIBNAME) $(OBJS)
$(OBJS):af.h dsp.h filter.h window.h
all: $(LIBNAME)
clean:
rm -f *.o *.a *~
distclean:
rm -f *.o *.a *~ .depend
dep: depend
depend:
$(CC) -MM $(CFLAGS) $(SRCS) 1>.depend
#
# include dependency files if they exist
#
ifneq ($(wildcard .depend),)
include .depend
endif

440
libaf/af.c Normal file
View File

@ -0,0 +1,440 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include "../config.h"
#include "../mp_msg.h"
#include "af.h"
// Static list of filters
extern af_info_t af_info_dummy;
extern af_info_t af_info_delay;
extern af_info_t af_info_channels;
extern af_info_t af_info_format;
extern af_info_t af_info_resample;
static af_info_t* filter_list[]={ \
&af_info_dummy,\
&af_info_delay,\
&af_info_channels,\
&af_info_format,\
&af_info_resample,\
NULL \
};
// Command line config switches
af_cfg_t af_cfg={\
0,\
0,\
0,\
0,\
NULL,\
};
// Initialization types
#define SLOW 1
#define FAST 2
#define FORCE 3
// The first and last filter in the list
static af_instance_t* first=NULL;
static af_instance_t* last=NULL;
// Storage for input and output data formats (set by init)
static af_data_t input;
static af_data_t output;
/* Find a filter in the static list of filters using it's name. This
function is used internally */
af_info_t* af_find(char*name)
{
int i=0;
while(filter_list[i]){
if(!strcmp(filter_list[i]->name,name))
return filter_list[i];
i++;
}
mp_msg(MSGT_AFILTER,MSGL_ERR,"Couldn't find audio filter '%s'\n",name);
return NULL;
}
// Function for creating a new filter of type name
af_instance_t* af_create(char* name)
{
// Allocate space for the new filter and reset all pointers
af_instance_t* new=malloc(sizeof(af_instance_t));
if(!new){
mp_msg(MSGT_AFILTER,MSGL_ERR,"Could not allocate memory\n");
return NULL;
}
memset(new,0,sizeof(af_instance_t));
// Find filter from name
new->info=af_find(name);
// Initialize the new filter
if(new->info && (AF_OK==new->info->open(new)))
return new;
free(new);
mp_msg(MSGT_AFILTER,MSGL_ERR,"Couldn't create audio filter '%s'\n",name);
return NULL;
}
/* Create and insert a new filter of type name before the filter in the
argument. This function can be called during runtime, the return
value is the new filter */
af_instance_t* af_prepend(af_instance_t* af, char* name)
{
// Create the new filter and make sure it is ok
af_instance_t* new=af_create(name);
if(!new)
return NULL;
// Update pointers
new->next=af;
if(af){
new->prev=af->prev;
af->prev=new;
}
else
last=new;
if(new->prev)
new->prev->next=new;
else
first=new;
return new;
}
/* Create and insert a new filter of type name after the filter in the
argument. This function can be called during runtime, the return
value is the new filter */
af_instance_t* af_append(af_instance_t* af, char* name)
{
// Create the new filter and make sure it is OK
af_instance_t* new=af_create(name);
if(!new)
return NULL;
// Update pointers
new->prev=af;
if(af){
new->next=af->next;
af->next=new;
}
else
first=new;
if(new->next)
new->next->prev=new;
else
last=new;
return new;
}
// Uninit and remove the filter "af"
void af_remove(af_instance_t* af)
{
if(!af) return;
// Detach pointers
if(af->prev)
af->prev->next=af->next;
else
first=af->next;
if(af->next)
af->next->prev=af->prev;
else
last=af->prev;
// Uninitialize af and free memory
af->uninit(af);
free(af);
}
/* Reinitializes all filters downstream from the filter given in the argument */
int af_reinit(af_instance_t* af)
{
if(!af)
return AF_ERROR;
do{
af_data_t in; // Format of the input to current filter
int rv=0; // Return value
// Check if this is the first filter
if(!af->prev)
memcpy(&in,&input,sizeof(af_data_t));
else
memcpy(&in,af->prev->data,sizeof(af_data_t));
// Reset just in case...
in.audio=NULL;
in.len=0;
rv = af->control(af,AF_CONTROL_REINIT,&in);
switch(rv){
case AF_OK:
break;
case AF_FALSE:{ // Configuration filter is needed
af_instance_t* new = NULL;
// Insert channels filter
if((af->prev?af->prev->data->nch:input.nch) != in.nch){
// Create channels filter
if(NULL == (new = af_prepend(af,"channels")))
return AF_ERROR;
// Set number of output channels
if(AF_OK != (rv = new->control(new,AF_CONTROL_CHANNELS,&in.nch)))
return rv;
// Initialize channels filter
if(!new->prev)
memcpy(&in,&input,sizeof(af_data_t));
else
memcpy(&in,new->prev->data,sizeof(af_data_t));
if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in)))
return rv;
}
// Insert format filter
if(((af->prev?af->prev->data->format:input.format) != in.format) ||
((af->prev?af->prev->data->bps:input.bps) != in.bps)){
// Create format filter
if(NULL == (new = af_prepend(af,"format")))
return AF_ERROR;
// Set output format
if(AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT,&in)))
return rv;
// Initialize format filter
if(!new->prev)
memcpy(&in,&input,sizeof(af_data_t));
else
memcpy(&in,new->prev->data,sizeof(af_data_t));
if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in)))
return rv;
}
if(!new) // Should _never_ happen
return AF_ERROR;
af=new;
break;
}
case AF_DETACH:{ // Filter is redundant and wants to be unloaded
af_instance_t* aft=af->prev;
af_remove(af);
if(aft)
af=aft;
else
af=first; // Restart configuration
break;
}
default:
mp_msg(MSGT_AFILTER,MSGL_ERR,"Reinit did not work, audio filter '%s' returned error code %i\n",af->info->name,rv);
return AF_ERROR;
}
af=af->next;
}while(af);
return AF_OK;
}
/* Find filter in the dynamic filter list using it's name This
function is used for finding already initialized filters */
af_instance_t* af_get(char* name)
{
af_instance_t* af=first;
while(af->next != NULL){
if(!strcmp(af->info->name,name))
return af;
af=af->next;
}
return NULL;
}
// Uninit and remove all filters
void af_uninit()
{
while(first)
af_remove(first);
}
/* Init read configuration and create filter list accordingly. In and
out contains the format of the current movie and the formate of the
preferred output respectively */
int af_init(af_data_t* in, af_data_t* out)
{
int cfg=SLOW; // configuration type
int i=0;
// Precaution in case caller is misbehaving
in->audio = out->audio = NULL;
in->len = out->len = 0;
// Figure out how fast the machine is
if(af_cfg.force)
cfg=af_cfg.force;
else{
# if defined(HAVE_SSE) || defined(HAVE_3DNOWEX)
cfg=FAST;
# else
cfg=SLOW;
# endif
}
// Input and output configuration
memcpy(&input,in,sizeof(af_data_t));
memcpy(&output,out,sizeof(af_data_t));
// Check if this is the first call
if(!first){
// Add all filters in the list (if there are any)
if(!af_cfg.list){
if(!af_append(first,"dummy")) // To make automatic format conversion work
return -1;
}
else{
while(af_cfg.list[i]){
if(!af_append(last,af_cfg.list[i++]))
return -1;
}
}
}
// Init filters
if(AF_OK != af_reinit(first))
return -1;
// Check output format
if(cfg!=FORCE){
af_instance_t* af = NULL; // New filter
// Check output frequency if not OK fix with resample
if(last->data->rate!=output.rate){
if(NULL==(af=af_get("resample"))){
if(cfg==SLOW){
if(!strcmp(first->info->name,"format"))
af = af_append(first,"resample");
else
af = af_prepend(first,"resample");
}
else{
if(!strcmp(last->info->name,"format"))
af = af_prepend(last,"resample");
else
af = af_append(last,"resample");
}
}
// Init the new filter
if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE,&output.rate)))
return -1;
if(AF_OK != af_reinit(af))
return -1;
}
// Check number of output channels fix if not OK
// If needed always inserted last -> easy to screw up other filters
if(last->data->nch!=output.nch){
if(!strcmp(last->info->name,"format"))
af = af_prepend(last,"channels");
else
af = af_append(last,"channels");
// Init the new filter
if(!af || (AF_OK != af->control(af,AF_CONTROL_CHANNELS,&output.nch)))
return -1;
if(AF_OK != af_reinit(af))
return -1;
}
// Check output format fix if not OK
if((last->data->format != output.format) || (last->data->bps != output.bps)){
if(strcmp(last->info->name,"format"))
af = af_append(last,"format");
else
af = last;
// Init the new filter
if(!af ||(AF_OK != af->control(af,AF_CONTROL_FORMAT,&output)))
return -1;
if(AF_OK != af_reinit(af))
return -1;
}
// Re init again just in case
if(AF_OK != af_reinit(first))
return -1;
if((last->data->format != output.format) || (last->data->bps != output.bps) ||
(last->data->nch!=output.nch) || (last->data->rate!=output.rate)){
// Something is stuffed audio out will not work
mp_msg(MSGT_AFILTER,MSGL_ERR,"Unable to setup filter system can not meet sound-card demands, please report this error on MPlayer development mailing list. \n");
af_uninit();
return -1;
}
}
return 0;
}
// Filter data chunk through the filters in the list
af_data_t* af_play(af_data_t* data)
{
af_instance_t* af=first;
// Iterate through all filters
do{
data=af->play(af,data);
af=af->next;
}while(af);
return data;
}
/* Helper function used to calculate the exact buffer length needed
when buffers are resized */
inline int af_lencalc(frac_t mul, int len){
register int q = len*mul.n;
return q/mul.d + q%mul.d;
}
/* Calculate how long the output from the filters will be given the
input length "len" */
int af_outputlen(int len)
{
af_instance_t* af=first;
frac_t mul = {1,1};
// Iterate through all filters
do{
mul.n *= af->mul.n;
mul.d *= af->mul.d;
af=af->next;
}while(af);
return af_lencalc(mul,len);
}
/* Calculate how long the input to the filters should be to produce a
certain output length, i.e. the return value of this function is
the input length required to produce the output length "len". */
int af_inputlen(int len)
{
af_instance_t* af=first;
frac_t mul = {1,1};
// Iterate through all filters
do{
mul.d *= af->mul.n;
mul.n *= af->mul.d;
af=af->next;
}while(af);
return af_lencalc(mul,len);
}
/* Helper function called by the macro with the same name this
function should not be called directly */
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->len);
mp_msg(MSGT_AFILTER,MSGL_V,"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){
mp_msg(MSGT_AFILTER,MSGL_ERR,"Could not allocate memory \n");
return AF_ERROR;
}
af->data->len=len;
return AF_OK;
}

160
libaf/af.h Normal file
View File

@ -0,0 +1,160 @@
#ifndef __aop_h__
#define __aop_h__
struct af_instance_s;
// Audio data chunk
typedef struct af_data_s
{
void* audio; // data buffer
int len; // buffer length
int rate; // sample rate
int nch; // number of channels
int format; // format
int bps; // bytes per sample
} af_data_t;
// Fraction, used to calculate buffer lengths
typedef struct frac_s
{
int n; // Numerator
int d; // Denominator
} frac_t;
/* Audio filter information not specific for current instance, but for
a specific filter */
typedef struct af_info_s
{
const char *info;
const char *name;
const char *author;
const char *comment;
int (*open)(struct af_instance_s* vf);
} af_info_t;
// Linked list of audio filters
typedef struct af_instance_s
{
af_info_t* info;
int (*control)(struct af_instance_s* af, int cmd, void* arg);
void (*uninit)(struct af_instance_s* af);
af_data_t* (*play)(struct af_instance_s* af, af_data_t* data);
void* setup; // setup data for this specific instance and filter
af_data_t* data; // configuration for outgoing data stream
struct af_instance_s* next;
struct af_instance_s* prev;
frac_t mul; /* length multiplier: how much does this instance change
the length of the buffer. */
}af_instance_t;
/*********************************************
// Control parameters
*/
/* The control system is divided into 3 levels
mandatory calls - all filters must answer to all of these
optional calls - are optional
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
// MANDATORY CALLS
/* Reinitialize filter. The optional argument contains the new
configuration in form of a af_data_t struct. If the filter does not
support the new format the struct should be changed and AF_FALSE
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 1 + AF_CONTROL_MANDATORY_BASE
// OPTIONAL CALLS
// FILTER SPECIFIC CALLS
// Set output rate in resample
#define AF_CONTROL_RESAMPLE 1 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Set output format in format
#define AF_CONTROL_FORMAT 2 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Set number of output channels in channels
#define AF_CONTROL_CHANNELS 3 + AF_CONTROL_FILTER_SPECIFIC_BASE
// Set delay length in delay
#define AF_CONTROL_SET_DELAY_LEN 4 + AF_CONTROL_FILTER_SPECIFIC_BASE
/*********************************************
// Return values
*/
#define AF_DETACH 2
#define AF_OK 1
#define AF_TRUE 1
#define AF_FALSE 0
#define AF_UNKNOWN -1
#define AF_ERROR -2
#define AF_NA -3
/*********************************************
// Command line configuration switches
*/
typedef struct af_cfg_s{
int rate;
int format;
int bps;
int force;
char** list;
}af_cfg_t;
// Export functions
/* Init read configuration and create filter list accordingly. In and
out contains the format of the current movie and the formate of the
prefered output respectively */
int af_init(af_data_t* in, af_data_t* out);
// Uninit and remove all filters
void af_uninit();
// Filter data chunk through the filters in the list
af_data_t* af_play(af_data_t* data);
/* Calculate how long the output from the filters will be given the
input length "len" */
int af_outputlen(int len);
/* Calculate how long the input to the filters should be to produce a
certain output length, i.e. the return value of this function is
the input length required to produce the output length "len". */
int af_inputlen(int len);
// Helper functions and macros used inside the audio filters
/* Helper function called by the macro with the same name only to be
called from inside filters */
int af_resize_local_buffer(af_instance_t* af, af_data_t* data);
/* Helper function used to calculate the exact buffer length needed
when buffers are resized */
int af_lencalc(frac_t mul, int len);
/* 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. */
#define RESIZE_LOCAL_BUFFER(a,d)\
((af->data->len < af_lencalc(af->mul,data->len))?af_resize_local_buffer(af,data):AF_OK)
#ifndef min
#define min(a,b)(((a)>(b))?(b):(a))
#endif
#ifndef max
#define max(a,b)(((a)>(b))?(a):(b))
#endif
#ifndef AUDIO_FILTER
extern af_cfg_t af_cfg;
#endif /* AUDIO_FILTER */
#endif

171
libaf/af_channels.c Normal file
View File

@ -0,0 +1,171 @@
/* Audio filter that adds and removes channels, according to the
command line parameter channels. It is stupid and can only add
silence or copy channels not mix or filter.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../config.h"
#include "../mp_msg.h"
#include "af.h"
// Local function for copying data
void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, int bps)
{
switch(bps){
case 1:{
int8_t* tin = (int8_t*)in;
int8_t* tout = (int8_t*)out;
tin += inos;
tout += outos;
len = len/ins;
while(len--){
*tout=*tin;
tin +=ins;
tout+=outs;
}
break;
}
case 2:{
int16_t* tin = (int16_t*)in;
int16_t* tout = (int16_t*)out;
tin += inos;
tout += outos;
len = len/(2*ins);
while(len--){
*tout=*tin;
tin +=ins;
tout+=outs;
}
break;
}
case 4:{
int32_t* tin = (int32_t*)in;
int32_t* tout = (int32_t*)out;
tin += inos;
tout += outos;
len = len/(4*ins);
while(len--){
*tout=*tin;
tin +=ins;
tout+=outs;
}
break;
}
case 8:{
int64_t* tin = (int64_t*)in;
int64_t* tout = (int64_t*)out;
tin += inos;
tout += outos;
len = len/(8*ins);
while(len--){
*tout=*tin;
tin +=ins;
tout+=outs;
}
break;
}
default:
mp_msg(MSGT_AFILTER,MSGL_ERR,"[channels] Unsupported number of bytes/sample: %i please report this error on the MPlayer mailing list. \n",bps);
}
}
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
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;
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;
case AF_CONTROL_CHANNELS:
// Reinit must be called after this function has been called
// Sanity check
if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > 6){
mp_msg(MSGT_AFILTER,MSGL_ERR,"[channels] The number of output channels must be between 1 and 6. Current value is%i \n",((int*)arg)[0]);
return AF_ERROR;
}
af->data->nch=((int*)arg)[0];
mp_msg(MSGT_AFILTER,MSGL_V,"[channels] Changing number of channels to %i\n",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);
}
// 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
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,af_lencalc(af->mul, c->len));
// 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);
}
}
// Set output data
c->audio = l->audio;
c->len = af_lencalc(af->mul, c->len);
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));
if(af->data == NULL)
return AF_ERROR;
return AF_OK;
}
// Description of this filter
af_info_t af_info_channels = {
"Insert or remove channels",
"channels",
"Anders",
"",
open
};

146
libaf/af_delay.c Normal file
View File

@ -0,0 +1,146 @@
/* This audio filter doesn't really do anything useful but serves an
example of how audio filters work. It delays the output signal by
the number of seconds set by delay=n where n is the number of
seconds.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../config.h"
#include "../mp_msg.h"
#include "af.h"
// Data for specific instances of this filter
typedef struct af_delay_s
{
void* buf; // data block used for delaying audio signal
int len; // local buffer length
float tlen; // Delay in seconds
}af_delay_t;
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
switch(cmd){
case AF_CONTROL_REINIT:{
af->data->rate = ((af_data_t*)arg)->rate;
af->data->nch = ((af_data_t*)arg)->nch;
af->data->format = ((af_data_t*)arg)->format;
af->data->bps = ((af_data_t*)arg)->bps;
return af->control(af,AF_CONTROL_SET_DELAY_LEN,&((af_delay_t*)af->setup)->tlen);
}
case AF_CONTROL_SET_DELAY_LEN:{
af_delay_t* s = (af_delay_t*)af->setup;
void* bt = s->buf; // Old buffer
int lt = s->len; // Old len
if(*((float*)arg) > 30 || *((float*)arg) < 0){
mp_msg(MSGT_AFILTER,MSGL_ERR,"Error setting delay length in af_delay. Delay must be between 0s and 30s\n");
s->len=0;
s->tlen=0.0;
return AF_ERROR;
}
// Set new len and allocate new buffer
s->tlen = *((float*)arg);
s->len = af->data->rate*af->data->bps*af->data->nch*(int)s->tlen;
s->buf = malloc(s->len);
mp_msg(MSGT_AFILTER,MSGL_DBG2,"[delay] Delaying audio output by %0.2fs\n",s->tlen);
mp_msg(MSGT_AFILTER,MSGL_DBG3,"[delay] Delaying audio output by %i bytes\n",s->len);
// Out of memory error
if(!s->buf){
s->len = 0;
free(bt);
return AF_ERROR;
}
// Clear the new buffer
memset(s->buf, 0, s->len);
/* Copy old buffer to avoid click in output
sound (at least most of it) and release it */
if(bt){
memcpy(s->buf,bt,min(lt,s->len));
free(bt);
}
return AF_OK;
}
}
return AF_UNKNOWN;
}
// Deallocate memory
static void uninit(struct af_instance_s* af)
{
if(af->data->audio)
free(af->data->audio);
if(af->data)
free(af->data);
if(((af_delay_t*)(af->setup))->buf)
free(((af_delay_t*)(af->setup))->buf);
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_delay_t* s = (af_delay_t*)af->setup; // Setup for this instance
if(AF_OK != RESIZE_LOCAL_BUFFER(af , data))
return NULL;
if(s->len > c->len){ // Delay bigger than buffer
// Copy beginning of buffer to beginning of output buffer
memcpy(l->audio,s->buf,c->len);
// Move buffer left
memcpy(s->buf,s->buf+c->len,s->len-c->len);
// Save away current audio to end of buffer
memcpy(s->buf+s->len-c->len,c->audio,c->len);
}
else{
// Copy end of previous block to beginning of output buffer
memcpy(l->audio,s->buf,s->len);
// Copy current block except end
memcpy(l->audio+s->len,c->audio,c->len-s->len);
// Save away end of current block for next call
memcpy(s->buf,c->audio+c->len-s->len,s->len);
}
// Set output data
c->audio=l->audio;
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_delay_t));
if(af->data == NULL || af->setup == NULL)
return AF_ERROR;
return AF_OK;
}
// Description of this filter
af_info_t af_info_delay = {
"Delay audio filter",
"delay",
"Anders",
"",
open
};

60
libaf/af_dummy.c Normal file
View File

@ -0,0 +1,60 @@
/* The name speaks for itself this filter is a dummy and will not blow
up regardless of what you do with it. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../config.h"
#include "../mp_msg.h"
#include "af.h"
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
switch(cmd){
case AF_CONTROL_REINIT:
memcpy(af->data,(af_data_t*)arg,sizeof(af_data_t));
mp_msg(MSGT_AFILTER,MSGL_V,"[dummy] Was reinitialized, rate=%iHz, nch = %i, format = 0x%08X and bps = %i\n",af->data->rate,af->data->nch,af->data->format,af->data->bps);
return AF_OK;
}
return AF_UNKNOWN;
}
// Deallocate memory
static void uninit(struct af_instance_s* af)
{
if(af->data)
free(af->data);
}
// Filter data through filter
static af_data_t* play(struct af_instance_s* af, af_data_t* data)
{
// Do something necessary to get rid of annoying warning during compile
if(!af)
printf("EEEK: Argument af == NULL in af_dummy.c play().");
return data;
}
// Allocate memory and set function pointers
static int open(af_instance_t* af){
af->control=control;
af->uninit=uninit;
af->play=play;
af->mul.d=1;
af->mul.n=1;
af->data=malloc(sizeof(af_data_t));
if(af->data == NULL)
return AF_ERROR;
return AF_OK;
}
// Description of this filter
af_info_t af_info_dummy = {
"dummy",
"dummy",
"Anders",
"",
open
};

291
libaf/af_format.c Normal file
View File

@ -0,0 +1,291 @@
/* This audio output filter changes the format of a data block. Valid
formats are: AFMT_U8, AFMT_S8, AFMT_S16_LE, AFMT_S16_BE
AFMT_U16_LE, AFMT_U16_BE, AFMT_S32_LE and AFMT_S32_BE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <limits.h>
#include "../config.h"
#include "../mp_msg.h"
#include "../libao2/afmt.h"
#include "af.h"
// Number of bits
#define B08 (0<<0)
#define B16 (1<<0)
#define B32 (2<<0)
#define NBITS_MASK (3<<0)
// Endianess
#define BE (0<<2) // Big Endian
#define LE (1<<2) // Little Endian
#define END_MASK (1<<2)
// Signed
#define US (0<<3) // Un Signed
#define SI (1<<3) // SIgned
#define SIGN_MASK (1<<3)
int decode(int format)
{
// Check input format
switch(format){
case(AFMT_U8):
return LE|B08|US;
case(AFMT_S8):
return LE|B08|SI; break;
case(AFMT_S16_LE):
return LE|B16|SI; break;
case(AFMT_S16_BE):
return BE|B16|SI; break;
case(AFMT_U16_LE):
return LE|B16|US; break;
case(AFMT_U16_BE):
return BE|B16|US; break;
case(AFMT_S32_LE):
return LE|B32|SI; break;
case(AFMT_S32_BE):
return BE|B32|SI; break;
case(AFMT_IMA_ADPCM):
case(AFMT_MU_LAW):
case(AFMT_A_LAW):
case(AFMT_MPEG):
case(AFMT_AC3):
mp_msg(MSGT_AFILTER,MSGL_ERR,"[af_format] Input audio format not yet supported \n");
return 0;
default:
//This can not happen ....
mp_msg(MSGT_AFILTER,MSGL_ERR,"Unrecognized input audio format\n");
return 0;
}
}
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
switch(cmd){
case AF_CONTROL_REINIT:
// Make sure this filter isn't redundant
if(af->data->format == ((af_data_t*)arg)->format && af->data->bps == ((af_data_t*)arg)->bps)
return AF_DETACH;
af->data->rate = ((af_data_t*)arg)->rate;
af->data->nch = ((af_data_t*)arg)->nch;
af->mul.n = af->data->bps;
af->mul.d = ((af_data_t*)arg)->bps;
return AF_OK;
case AF_CONTROL_FORMAT:
// Reinit must be called after this function has been called
// Sanity check for sample format
if(0 == ((int)af->setup=decode(((af_data_t*)arg)->format)))
return AF_ERROR;
af->data->format = ((af_data_t*)arg)->format;
// Sanity check for bytes per sample
if(((af_data_t*)arg)->bps != 4 && ((af_data_t*)arg)->bps != 2 && ((af_data_t*)arg)->bps != 1){
mp_msg(MSGT_AFILTER,MSGL_ERR,"[format] The number of output bytes per sample must be 1, 2 or 4. Current value is%i \n",((af_data_t*)arg)->bps);
return AF_ERROR;
}
af->data->bps=((af_data_t*)arg)->bps;
mp_msg(MSGT_AFILTER,MSGL_STATUS,"[format] Changing number sample format to 0x%08X and/or bytes per sample to %i \n",af->data->format,af->data->bps);
return AF_OK;
}
return AF_UNKNOWN;
}
// Deallocate memory
static void uninit(struct af_instance_s* af)
{
if(af->data)
free(af->data);
(int)af->setup = 0;
}
// Filter data through filter
static af_data_t* play(struct af_instance_s* af, af_data_t* data)
{
af_data_t* l = af->data; // Local data
void* la = NULL; // Local audio
int lf = (int)af->setup; // Local format
af_data_t* c = data; // Current working data
void* ca = c->audio; // Current audio
int cf = decode(c->format); // Current format
register int i = 0; // Counter
int len = c->len>>(cf&NBITS_MASK); // Loop end
if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
return NULL;
la = l->audio;
// Change to little endian
if((cf&END_MASK)!=LE){
switch(cf&NBITS_MASK){
case(B16):{
register uint16_t s;
for(i=1;i<len;i++){
s=((uint16_t*)ca)[i];
((uint16_t*)ca)[i]=(uint16_t)(((s&0x00FF)<<8) | (s&0xFF00)>>8);
}
}
break;
case(B32):{
register uint32_t s;
for(i=1;i<len;i++){
s=((uint32_t*)ca)[i];
((uint32_t*)ca)[i]=(uint32_t)(((s&0x000000FF)<<24) | ((s&0x0000FF00)<<8) |
((s&0x00FF0000)>>8) | ((s&0xFF000000)>>24));
}
}
break;
}
}
// Change signed/unsigned
if((cf&SIGN_MASK) != (lf&SIGN_MASK)){
switch((cf&NBITS_MASK)){
case(B08):
switch(cf&SIGN_MASK){
case(US):
for(i=0;i<len;i++)
((int8_t*)ca)[i]=(int8_t)(SCHAR_MIN+((int)((uint8_t*)ca)[i]));
break;
case(SI):
for(i=0;i<len;i++)
((uint8_t*)ca)[i]=(uint8_t)(SCHAR_MAX+((int)((int8_t*)ca)[i]));
break;
}
break;
case(B16):
switch(cf&SIGN_MASK){
case(US):
for(i=0;i<len;i++)
((int16_t*)ca)[i]=(int16_t)(SHRT_MIN+((int)((uint16_t*)ca)[i]));
break;
case(SI):
for(i=0;i<len;i++)
((uint16_t*)ca)[i]=(uint16_t)(SHRT_MAX+((int)((int16_t*)ca)[i]));
break;
}
break;
case(B32):
switch(cf&SIGN_MASK){
case(US):
for(i=0;i<len;i++)
((int32_t*)ca)[i]=(int32_t)(INT_MIN+((uint32_t*)ca)[i]);
break;
case(SI):
for(i=0;i<len;i++)
((uint32_t*)ca)[i]=(uint32_t)(INT_MAX+((int32_t*)ca)[i]);
break;
}
break;
}
}
// Change the number of bits
if((cf&NBITS_MASK) == (lf&NBITS_MASK)){
memcpy(la,ca,c->len);
} else {
switch(cf&NBITS_MASK){
case(B08):
switch(lf&NBITS_MASK){
case(B16):
for(i=1;i<len;i++)
((uint16_t*)la)[i]=((uint16_t)((uint8_t*)ca)[i])<<8;
break;
case(B32):
for(i=1;i<len;i++)
((uint32_t*)la)[i]=((uint32_t)((uint8_t*)ca)[i])<<24;
break;
}
break;
case(B16):
switch(lf&NBITS_MASK){
case(B08):
for(i=0;i<len;i++)
((uint8_t*)la)[i]=(uint8_t)((((uint16_t*)ca)[i])>>8);
break;
case(B32):
for(i=1;i<len;i++)
((uint32_t*)la)[i]=((uint32_t)((uint16_t*)ca)[i])<<16;
break;
}
break;
case(B32):
switch(lf&NBITS_MASK){
case(B08):
for(i=0;i<len;i++)
((uint8_t*)la)[i]=(uint8_t)((((uint32_t*)ca)[i])>>24);
break;
case(B16):
for(i=1;i<len;i++)
((uint16_t*)la)[i]=(uint16_t)((((uint32_t*)ca)[i])>>16);
break;
}
break;
}
}
// Switch to the correct endainess (again the problem with sun?)
if((lf&END_MASK)!=LE){
switch(cf&NBITS_MASK){
case(B16):{
register uint16_t s;
for(i=1;i<len;i++){
s=((uint16_t*)la)[i];
((uint16_t*)la)[i]=(uint16_t)(((s&0x00FF)<<8) | (s&0xFF00)>>8);
}
}
break;
case(B32):{
register uint32_t s;
for(i=1;i<len;i++){
s=((uint32_t*)la)[i];
((uint32_t*)la)[i]=(uint32_t)(((s&0x000000FF)<<24) | ((s&0x0000FF00)<<8) |
((s&0x00FF0000)>>8) | ((s&0xFF000000)>>24));
}
}
break;
}
}
// Set output data
// Make sure no samples are lost
c->len = (c->len*l->bps)/c->bps;
c->audio = l->audio;
c->bps = l->bps;
c->format = l->format;
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));
if(af->data == NULL)
return AF_ERROR;
(int)af->setup = 0;
return AF_OK;
}
// Description of this filter
af_info_t af_info_format = {
"Sample format conversion",
"format",
"Anders",
"",
open
};

340
libaf/af_resample.c Normal file
View File

@ -0,0 +1,340 @@
/*=============================================================================
//
// 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 audio filter changes the sample rate. */
#define PLUGIN
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include "../config.h"
#include "../mp_msg.h"
#include "../libao2/afmt.h"
#include "af.h"
#include "dsp.h"
/* Below definition selects the length of each poly phase component.
Valid definitions are L8 and L16, where the number denotes the
length of the filter. This definition affects the computational
complexity (see play()), the performance (see filter.h) and the
memory usage. The filterlenght is choosen to 8 if the machine is
slow and to 16 if the machine is fast and has MMX.
*/
#if defined(HAVE_SSE) && !defined(HAVE_3DNOW) // This machine is slow
#define L 8 // Filter length
// Unrolled loop to speed up execution
#define FIR(x,w,y){ \
int16_t a = (w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3]) >> 16; \
int16_t b = (w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7]) >> 16; \
(y[0]) = a+b; \
}
#else /* Fast machine */
#define L 16
// Unrolled loop to speed up execution
#define FIR(x,w,y){ \
int16_t a = (w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] ) >> 16; \
int16_t b = (w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] ) >> 16; \
int16_t c = (w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11]) >> 16; \
int16_t d = (w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15]) >> 16; \
y[0] = (a+b+c+d) >> 1; \
}
#endif /* Fast machine */
// Macro to add data to circular que
#define ADDQUE(xi,xq,in)\
xq[xi]=xq[xi+L]=(*in);\
xi=(--xi)&(L-1);
// local data
typedef struct af_resample_s
{
int16_t* w; // Current filter weights
int16_t** xq; // Circular buffers
int16_t xi; // Index for circular buffers
int16_t wi; // Index for w
uint16_t i; // Number of new samples to put in x queue
uint16_t dn; // Down sampling factor
uint16_t up; // Up sampling factor
} af_resample_t;
// Euclids algorithm for calculating Greatest Common Divisor GCD(a,b)
inline int gcd(register int a, register int b)
{
register int r = min(a,b);
a=max(a,b);
b=r;
r=a%b;
while(r!=0){
a=b;
b=r;
r=a%b;
}
return b;
}
static int upsample(af_data_t* c,af_data_t* l, af_resample_t* s)
{
uint16_t ci = l->nch; // Index for channels
uint16_t len = 0; // Number of input samples
uint16_t nch = l->nch; // Number of channels
uint16_t inc = s->up/s->dn;
uint16_t level = s->up%s->dn;
uint16_t up = s->up;
uint16_t dn = s->dn;
register int16_t* w = s->w;
register uint16_t wi = 0;
register uint16_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 uint16_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)
{
uint16_t ci = l->nch; // Index for channels
uint16_t len = 0; // Number of output samples
uint16_t nch = l->nch; // Number of channels
uint16_t inc = s->dn/s->up;
uint16_t level = s->dn%s->up;
uint16_t up = s->up;
uint16_t dn = s->dn;
register uint16_t i = 0;
register uint16_t wi = 0;
register uint16_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;
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){
// 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++;
}
}
}
// Save values that needs to be kept for next time
s->wi = wi;
s->xi = xi;
s->i = i;
return len;
}
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
switch(cmd){
case AF_CONTROL_REINIT:{
af_resample_t* s = (af_resample_t*)af->setup;
af_data_t* n = (af_data_t*)arg; // New configureation
int i,d = 0;
int rv = AF_OK;
// Make sure this filter isn't redundant
if(af->data->rate == n->rate)
return AF_DETACH;
// Create space for circular bufers (if nesessary)
if(af->data->nch != n->nch){
// First free the old ones
if(s->xq){
for(i=1;i<af->data->nch;i++)
if(s->xq[i])
free(s->xq[i]);
free(s->xq);
}
// ... then create new
s->xq = malloc(n->nch*sizeof(int16_t*));
for(i=0;i<n->nch;i++)
s->xq[i] = malloc(2*L*sizeof(int16_t));
s->xi = 0;
}
// Set parameters
af->data->nch = n->nch;
af->data->format = AFMT_S16_LE;
af->data->bps = 2;
if(af->data->format != n->format || af->data->bps != n->bps)
rv = AF_FALSE;
n->format = AFMT_S16_LE;
n->bps = 2;
// Calculate up and down sampling factors
d=gcd(af->data->rate,n->rate);
// Check if the the design needs to be redone
if(s->up != af->data->rate/d || s->dn != n->rate/d){
float* w;
float* wt;
float fc;
int j;
s->up = af->data->rate/d;
s->dn = n->rate/d;
// Calculate cuttof frequency for filter
fc = 1/(float)(max(s->up,s->dn));
// Allocate space for polyphase filter bank and protptype filter
w = malloc(sizeof(float) * s->up *L);
if(NULL != s->w)
free(s->w);
s->w = malloc(L*s->up*sizeof(int16_t));
// Design prototype filter type using Kaiser window with beta = 10
if(NULL == w || NULL == s->w ||
-1 == design_fir(s->up*L, w, &fc, LP|KAISER , 10.0)){
mp_msg(MSGT_AFILTER,MSGL_ERR,"[resample] Unable to design prototype filter.\n");
return AF_ERROR;
}
// Copy data from prototype to polyphase filter
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));
wt++;
}
}
free(w);
mp_msg(MSGT_AFILTER,MSGL_V,"[resample] New filter designed up: %i down: %i\n", s->up, s->dn);
}
// Set multiplier
af->mul.n = s->up;
af->mul.d = s->dn;
return rv;
}
case AF_CONTROL_RESAMPLE:
// Reinit must be called after this function has been called
// Sanity check
if(((int*)arg)[0] <= 8000 || ((int*)arg)[0] > 192000){
mp_msg(MSGT_AFILTER,MSGL_ERR,"[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];
mp_msg(MSGT_AFILTER,MSGL_STATUS,"[resample] Changing sample rate to %iHz\n",af->data->rate);
return AF_OK;
}
return AF_UNKNOWN;
}
// Deallocate memory
static void uninit(struct af_instance_s* af)
{
if(af->data)
free(af->data);
}
// Filter data through filter
static af_data_t* play(struct af_instance_s* af, af_data_t* data)
{
int len = 0; // Length of output data
af_data_t* c = data; // Current working data
af_data_t* l = af->data; // Local data
af_resample_t* s = (af_resample_t*)af->setup;
if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
return NULL;
// Run resampling
if(s->up>s->dn)
len = upsample(c,l,s);
else
len = downsample(c,l,s);
// Set output data
c->audio = l->audio;
c->len = len*2;
c->rate = l->rate;
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_resample_t));
if(af->data == NULL || af->setup == NULL)
return AF_ERROR;
return AF_OK;
}
// Description of this plugin
af_info_t af_info_resample = {
"Sample frequency conversion",
"resample",
"Anders",
"",
open
};

22
libaf/dsp.h Normal file
View File

@ -0,0 +1,22 @@
/*=============================================================================
//
// 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
//
//=============================================================================
*/
#ifndef _DSP_H
#define _DSP_H 1
/* Implementation of routines used for DSP */
/* Size of floating point type used in routines */
#define _ftype_t float
#include <window.h>
#include <filter.h>
#endif

257
libaf/filter.c Normal file
View File

@ -0,0 +1,257 @@
/*=============================================================================
//
// This software has been released under the terms of the GNU Public
// license. See http://www.gnu.org/copyleft/gpl.html for details.
//
// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
//
//=============================================================================
*/
/* Design and implementation of different types of digital filters
*/
#include <math.h>
#include "dsp.h"
/* C implementation of FIR filter y=w*x
n number of filter taps, where mod(n,4)==0
w filter taps
x input signal must be a circular buffer which is indexed backwards
*/
inline _ftype_t fir(register unsigned int n, _ftype_t* w, _ftype_t* x)
{
register _ftype_t y; // Output
y = 0.0;
do{
n--;
y+=w[n]*x[n];
}while(n != 0);
return y;
}
/* C implementation of parallel FIR filter y(k)=w(k) * x(k) (where * denotes convolution)
n number of filter taps, where mod(n,4)==0
d number of filters
xi current index in xq
w filter taps k by n big
x input signal must be a circular buffers which are indexed backwards
y output buffer
s output buffer stride
*/
inline _ftype_t* pfir(unsigned int n, unsigned int d, unsigned int xi, _ftype_t** w, _ftype_t** x, _ftype_t* y, unsigned int s)
{
register _ftype_t* xt = *x + xi;
register _ftype_t* wt = *w;
register int nt = 2*n;
while(d-- > 0){
*y = fir(n,wt,xt);
wt+=n;
xt+=nt;
y+=s;
}
return y;
}
/* Add new data to circular queue designed to be used with a parallel
FIR filter, with d filters. xq is the circular queue, in pointing
at the new samples, xi current index in xq and n the length of the
filter. xq must be n*2 by k big, s is the index for in.
*/
inline int updatepq(unsigned int n, unsigned int d, unsigned int xi, _ftype_t** xq, _ftype_t* in, unsigned int s)
{
register _ftype_t* txq = *xq + xi;
register int nt = n*2;
while(d-- >0){
*txq= *(txq+n) = *in;
txq+=nt;
in+=s;
}
return (++xi)&(n-1);
}
/* Design FIR filter using the Window method
n filter length must be odd for HP and BS filters
w buffer for the filter taps (must be n long)
fc cutoff frequencies (1 for LP and HP, 2 for BP and BS)
0 < fc < 1 where 1 <=> Fs/2
flags window and filter type as defined in filter.h
variables are ored together: i.e. LP|HAMMING will give a
low pass filter designed using a hamming window
opt beta constant used only when designing using kaiser windows
returns 0 if OK, -1 if fail
*/
int design_fir(unsigned int n, _ftype_t* w, _ftype_t* fc, unsigned int flags, _ftype_t opt)
{
unsigned int o = n & 1; // Indicator for odd filter length
unsigned int end = ((n + 1) >> 1) - o; // Loop end
unsigned int i; // Loop index
_ftype_t k1 = 2 * M_PI; // 2*pi*fc1
_ftype_t k2 = 0.5 * (_ftype_t)(1 - o);// Constant used if the filter has even length
_ftype_t k3; // 2*pi*fc2 Constant used in BP and BS design
_ftype_t g = 0.0; // Gain
_ftype_t t1,t2,t3; // Temporary variables
_ftype_t fc1,fc2; // Cutoff frequencies
// Sanity check
if(!w || (n == 0)) return -1;
// Get window coefficients
switch(flags & WINDOW_MASK){
case(BOXCAR):
boxcar(n,w); break;
case(TRIANG):
triang(n,w); break;
case(HAMMING):
hamming(n,w); break;
case(HANNING):
hanning(n,w); break;
case(BLACKMAN):
blackman(n,w); break;
case(FLATTOP):
flattop(n,w); break;
case(KAISER):
kaiser(n,w,opt); break;
default:
return -1;
}
if(flags & (LP | HP)){
fc1=*fc;
// Cutoff frequency must be < 0.5 where 0.5 <=> Fs/2
fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25;
k1 *= fc1;
if(flags & LP){ // Low pass filter
// If the filter length is odd, there is one point which is exactly
// in the middle. The value at this point is 2*fCutoff*sin(x)/x,
// where x is zero. To make sure nothing strange happens, we set this
// value separately.
if (o){
w[end] = fc1 * w[end] * 2.0;
g=w[end];
}
// Create filter
for (i=0 ; i<end ; i++){
t1 = (_ftype_t)(i+1) - k2;
w[end-i-1] = w[n-end+i] = w[end-i-1] * sin(k1 * t1)/(M_PI * t1); // Sinc
g += 2*w[end-i-1]; // Total gain in filter
}
}
else{ // High pass filter
if (!o) // High pass filters must have odd length
return -1;
w[end] = 1.0 - (fc1 * w[end] * 2.0);
g= w[end];
// Create filter
for (i=0 ; i<end ; i++){
t1 = (_ftype_t)(i+1);
w[end-i-1] = w[n-end+i] = -1 * w[end-i-1] * sin(k1 * t1)/(M_PI * t1); // Sinc
g += ((i&1) ? (2*w[end-i-1]) : (-2*w[end-i-1])); // Total gain in filter
}
}
}
if(flags & (BP | BS)){
fc1=fc[0];
fc2=fc[1];
// Cutoff frequencies must be < 1.0 where 1.0 <=> Fs/2
fc1 = ((fc1 <= 1.0) && (fc1 > 0.0)) ? fc1/2 : 0.25;
fc2 = ((fc2 <= 1.0) && (fc2 > 0.0)) ? fc2/2 : 0.25;
k3 = k1 * fc2; // 2*pi*fc2
k1 *= fc1; // 2*pi*fc1
if(flags & BP){ // Band pass
// Calculate center tap
if (o){
g=w[end]*(fc1+fc2);
w[end] = (fc2 - fc1) * w[end] * 2.0;
}
// Create filter
for (i=0 ; i<end ; i++){
t1 = (_ftype_t)(i+1) - k2;
t2 = sin(k3 * t1)/(M_PI * t1); // Sinc fc2
t3 = sin(k1 * t1)/(M_PI * t1); // Sinc fc1
g += w[end-i-1] * (t3 + t2); // Total gain in filter
w[end-i-1] = w[n-end+i] = w[end-i-1] * (t2 - t3);
}
}
else{ // Band stop
if (!o) // Band stop filters must have odd length
return -1;
w[end] = 1.0 - (fc2 - fc1) * w[end] * 2.0;
g= w[end];
// Create filter
for (i=0 ; i<end ; i++){
t1 = (_ftype_t)(i+1);
t2 = sin(k1 * t1)/(M_PI * t1); // Sinc fc1
t3 = sin(k3 * t1)/(M_PI * t1); // Sinc fc2
w[end-i-1] = w[n-end+i] = w[end-i-1] * (t2 - t3);
g += 2*w[end-i-1]; // Total gain in filter
}
}
}
// Normalize gain
g=1/g;
for (i=0; i<n; i++)
w[i] *= g;
return 0;
}
/* Design polyphase FIR filter from prototype filter
n length of prototype filter
k number of polyphase components
w prototype filter taps
pw Parallel FIR filter
g Filter gain
flags FWD forward indexing
REW reverse indexing
ODD multiply every 2nd filter tap by -1 => HP filter
returns 0 if OK, -1 if fail
*/
int design_pfir(unsigned int n, unsigned int k, _ftype_t* w, _ftype_t** pw, _ftype_t g, unsigned int flags)
{
int l = (int)n/k; // Length of individual FIR filters
int i; // Counters
int j;
_ftype_t t; // g * w[i]
// Sanity check
if(l<1 || k<1 || !w || !pw)
return -1;
// Do the stuff
if(flags&REW){
for(j=l-1;j>-1;j--){//Columns
for(i=0;i<(int)k;i++){//Rows
t=g * *w++;
pw[i][j]=t * ((flags & ODD) ? ((j & 1) ? -1 : 1) : 1);
}
}
}
else{
for(j=0;j<l;j++){//Columns
for(i=0;i<(int)k;i++){//Rows
t=g * *w++;
pw[i][j]=t * ((flags & ODD) ? ((j & 1) ? 1 : -1) : 1);
}
}
}
return -1;
}

65
libaf/filter.h Normal file
View File

@ -0,0 +1,65 @@
/*=============================================================================
//
// This software has been released under the terms of the GNU Public
// license. See http://www.gnu.org/copyleft/gpl.html for details.
//
// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
//
//=============================================================================
*/
#if !defined _DSP_H
# error "Never use <filter.h> directly; include <dsp.h> instead"
#endif
#ifndef _FILTER_H
#define _FILTER_H 1
// Design and implementation of different types of digital filters
// Flags used for filter design
// Filter characteristics
#define LP 0x00010000 // Low pass
#define HP 0x00020000 // High pass
#define BP 0x00040000 // Band pass
#define BS 0x00080000 // Band stop
#define TYPE_MASK 0x000F0000
// Window types
#define BOXCAR 0x00000001
#define TRIANG 0x00000002
#define HAMMING 0x00000004
#define HANNING 0x00000008
#define BLACKMAN 0x00000010
#define FLATTOP 0x00000011
#define KAISER 0x00000012
#define WINDOW_MASK 0x0000001F
// Parallel filter design
#define FWD 0x00000001 // Forward indexing of polyphase filter
#define REW 0x00000002 // Reverse indexing of polyphase filter
#define ODD 0x00000010 // Make filter HP
// Exported functions
extern _ftype_t fir(unsigned int n, _ftype_t* w, _ftype_t* x);
extern _ftype_t* pfir(unsigned int n, unsigned int k, unsigned int xi, _ftype_t** w, _ftype_t** x, _ftype_t* y, unsigned int s);
extern int updateq(unsigned int n, unsigned int xi, _ftype_t* xq, _ftype_t* in);
extern int updatepq(unsigned int n, unsigned int k, unsigned int xi, _ftype_t** xq, _ftype_t* in, unsigned int s);
extern int design_fir(unsigned int n, _ftype_t* w, _ftype_t* fc, unsigned int flags, _ftype_t opt);
extern int design_pfir(unsigned int n, unsigned int k, _ftype_t* w, _ftype_t** pw, _ftype_t g, unsigned int flags);
/* Add new data to circular queue designed to be used with a FIR
filter. xq is the circular queue, in pointing at the new sample, xi
current index for xq and n the length of the filter. xq must be n*2
long.
*/
#define updateq(n,xi,xq,in)\
xq[xi]=xq[xi+n]=*in;\
xi=(++xi)&(n-1);
#endif

203
libaf/window.c Normal file
View File

@ -0,0 +1,203 @@
/*=============================================================================
//
// This software has been released under the terms of the GNU Public
// license. See http://www.gnu.org/copyleft/gpl.html for details.
//
// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
//
//=============================================================================
*/
/* Calculates a number of window functions. The following window
functions are currently implemented: Boxcar, Triang, Hanning,
Hamming, Blackman, Flattop and Kaiser. In the function call n is
the number of filter taps and w the buffer in which the filter
coefficients will be stored.
*/
#include <math.h>
#include "dsp.h"
/*
// Boxcar
//
// n window length
// w buffer for the window parameters
*/
void boxcar(int n, _ftype_t* w)
{
int i;
// Calculate window coefficients
for (i=0 ; i<n ; i++)
w[i] = 1.0;
}
/*
// Triang a.k.a Bartlett
//
// | (N-1)|
// 2 * |k - -----|
// | 2 |
// w = 1.0 - ---------------
// N+1
// n window length
// w buffer for the window parameters
*/
void triang(int n, _ftype_t* w)
{
_ftype_t k1 = (_ftype_t)(n & 1);
_ftype_t k2 = 1/((_ftype_t)n + k1);
int end = (n + 1) >> 1;
int i;
// Calculate window coefficients
for (i=0 ; i<end ; i++)
w[i] = w[n-i-1] = (2.0*((_ftype_t)(i+1))-(1.0-k1))*k2;
}
/*
// Hanning
// 2*pi*k
// w = 0.5 - 0.5*cos(------), where 0 < k <= N
// N+1
// n window length
// w buffer for the window parameters
*/
void hanning(int n, _ftype_t* w)
{
int i;
_ftype_t k = 2*M_PI/((_ftype_t)(n+1)); // 2*pi/(N+1)
// Calculate window coefficients
for (i=0; i<n; i++)
*w++ = 0.5*(1.0 - cos(k*(_ftype_t)(i+1)));
}
/*
// Hamming
// 2*pi*k
// w(k) = 0.54 - 0.46*cos(------), where 0 <= k < N
// N-1
//
// n window length
// w buffer for the window parameters
*/
void hamming(int n,_ftype_t* w)
{
int i;
_ftype_t k = 2*M_PI/((_ftype_t)(n-1)); // 2*pi/(N-1)
// Calculate window coefficients
for (i=0; i<n; i++)
*w++ = 0.54 - 0.46*cos(k*(_ftype_t)i);
}
/*
// Blackman
// 2*pi*k 4*pi*k
// w(k) = 0.42 - 0.5*cos(------) + 0.08*cos(------), where 0 <= k < N
// N-1 N-1
//
// n window length
// w buffer for the window parameters
*/
void blackman(int n,_ftype_t* w)
{
int i;
_ftype_t k1 = 2*M_PI/((_ftype_t)(n-1)); // 2*pi/(N-1)
_ftype_t k2 = 2*k1; // 4*pi/(N-1)
// Calculate window coefficients
for (i=0; i<n; i++)
*w++ = 0.42 - 0.50*cos(k1*(_ftype_t)i) + 0.08*cos(k2*(_ftype_t)i);
}
/*
// Flattop
// 2*pi*k 4*pi*k
// w(k) = 0.2810638602 - 0.5208971735*cos(------) + 0.1980389663*cos(------), where 0 <= k < N
// N-1 N-1
//
// n window length
// w buffer for the window parameters
*/
void flattop(int n,_ftype_t* w)
{
int i;
_ftype_t k1 = 2*M_PI/((_ftype_t)(n-1)); // 2*pi/(N-1)
_ftype_t k2 = 2*k1; // 4*pi/(N-1)
// Calculate window coefficients
for (i=0; i<n; i++)
*w++ = 0.2810638602 - 0.5208971735*cos(k1*(_ftype_t)i) + 0.1980389663*cos(k2*(_ftype_t)i);
}
/* Computes the 0th order modified Bessel function of the first kind.
// (Needed to compute Kaiser window)
//
// y = sum( (x/(2*n))^2 )
// n
*/
#define BIZ_EPSILON 1E-21 // Max error acceptable
_ftype_t besselizero(_ftype_t x)
{
_ftype_t temp;
_ftype_t sum = 1.0;
_ftype_t u = 1.0;
_ftype_t halfx = x/2.0;
int n = 1;
do {
temp = halfx/(_ftype_t)n;
u *=temp * temp;
sum += u;
n++;
} while (u >= BIZ_EPSILON * sum);
return(sum);
}
/*
// Kaiser
//
// n window length
// w buffer for the window parameters
// b beta parameter of Kaiser window, Beta >= 1
//
// Beta trades the rejection of the low pass filter against the
// transition width from passband to stop band. Larger Beta means a
// slower transition and greater stop band rejection. See Rabiner and
// Gold (Theory and Application of DSP) under Kaiser windows for more
// about Beta. The following table from Rabiner and Gold gives some
// feel for the effect of Beta:
//
// All ripples in dB, width of transition band = D*N where N = window
// length
//
// BETA D PB RIP SB RIP
// 2.120 1.50 +-0.27 -30
// 3.384 2.23 0.0864 -40
// 4.538 2.93 0.0274 -50
// 5.658 3.62 0.00868 -60
// 6.764 4.32 0.00275 -70
// 7.865 5.0 0.000868 -80
// 8.960 5.7 0.000275 -90
// 10.056 6.4 0.000087 -100
*/
void kaiser(int n, _ftype_t* w, _ftype_t b)
{
_ftype_t tmp;
_ftype_t k1 = 1.0/besselizero(b);
int k2 = 1 - (n & 1);
int end = (n + 1) >> 1;
int i;
// Calculate window coefficients
for (i=0 ; i<end ; i++){
tmp = (_ftype_t)(2*i + k2) / ((_ftype_t)n - 1.0);
w[end-(1&(!k2))+i] = w[end-1-i] = k1 * besselizero(b*sqrt(1.0 - tmp*tmp));
}
}

33
libaf/window.h Normal file
View File

@ -0,0 +1,33 @@
/*=============================================================================
//
// This software has been released under the terms of the GNU Public
// license. See http://www.gnu.org/copyleft/gpl.html for details.
//
// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
//
//=============================================================================
*/
/* Calculates a number of window functions. The following window
functions are currently implemented: Boxcar, Triang, Hanning,
Hamming, Blackman, Flattop and Kaiser. In the function call n is
the number of filter taps and w the buffer in which the filter
coefficients will be stored.
*/
#if !defined _DSP_H
# error "Never use <window.h> directly; include <dsp.h> instead"
#endif
#ifndef _WINDOW_H
#define _WINDOW_H 1
extern void boxcar(int n, _ftype_t* w);
extern void triang(int n, _ftype_t* w);
extern void hanning(int n, _ftype_t* w);
extern void hamming(int n,_ftype_t* w);
extern void blackman(int n,_ftype_t* w);
extern void flattop(int n,_ftype_t* w);
extern void kaiser(int n, _ftype_t* w,_ftype_t b);
#endif

View File

@ -81,6 +81,8 @@ extern int verbose; // defined in mplayer.c
#define MSGT_VOBSUB 35
#define MSGT_SUBREADER 36
#define MSGT_AFILTER 37 // Audio filter messages
#define MSGT_MAX 64
void mp_msg_init();