changeset 7568:d08513b9fed6

Adding new audio output filter layer libaf
author anders
date Tue, 01 Oct 2002 06:45:08 +0000
parents 85e9956a6727
children 5e956ff37e91
files Makefile libaf/Makefile libaf/af.c libaf/af.h libaf/af_channels.c libaf/af_delay.c libaf/af_dummy.c libaf/af_format.c libaf/af_resample.c libaf/dsp.h libaf/filter.c libaf/filter.h libaf/window.c libaf/window.h mp_msg.h
diffstat 15 files changed, 2234 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Sep 30 21:46:54 2002 +0000
+++ b/Makefile	Tue Oct 01 06:45:08 2002 +0000
@@ -45,13 +45,13 @@
 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 @@
 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 @@
 .c.o:
 	$(CC) -c $(CFLAGS) -o $@ $<
 
+libaf/libaf.a:
+	$(MAKE) -C libaf
+
 libmpdvdkit2/libmpdvdkit.a:
 	$(MAKE) -C libmpdvdkit2
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/Makefile	Tue Oct 01 06:45:08 2002 +0000
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/af.c	Tue Oct 01 06:45:08 2002 +0000
@@ -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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/af.h	Tue Oct 01 06:45:08 2002 +0000
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/af_channels.c	Tue Oct 01 06:45:08 2002 +0000
@@ -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
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/af_delay.c	Tue Oct 01 06:45:08 2002 +0000
@@ -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
+};
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/af_dummy.c	Tue Oct 01 06:45:08 2002 +0000
@@ -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
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/af_format.c	Tue Oct 01 06:45:08 2002 +0000
@@ -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
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/af_resample.c	Tue Oct 01 06:45:08 2002 +0000
@@ -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
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/dsp.h	Tue Oct 01 06:45:08 2002 +0000
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/filter.c	Tue Oct 01 06:45:08 2002 +0000
@@ -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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/filter.h	Tue Oct 01 06:45:08 2002 +0000
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/window.c	Tue Oct 01 06:45:08 2002 +0000
@@ -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));
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/window.h	Tue Oct 01 06:45:08 2002 +0000
@@ -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
--- a/mp_msg.h	Mon Sep 30 21:46:54 2002 +0000
+++ b/mp_msg.h	Tue Oct 01 06:45:08 2002 +0000
@@ -81,6 +81,8 @@
 #define MSGT_VOBSUB 35
 #define MSGT_SUBREADER 36
 
+#define MSGT_AFILTER 37  // Audio filter messages
+
 #define MSGT_MAX 64
 
 void mp_msg_init();