summaryrefslogtreecommitdiffstats
path: root/libaf
diff options
context:
space:
mode:
authoranders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-10-01 06:45:08 +0000
committeranders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-10-01 06:45:08 +0000
commit1f6c494641c4ca99eec7a9f47818526c72789439 (patch)
tree17bf220c1c1ac1144dfa8212f09444e51c248a26 /libaf
parentc0091278d8f15580eecebfc8c454fba250cf4b94 (diff)
downloadmpv-1f6c494641c4ca99eec7a9f47818526c72789439.tar.bz2
mpv-1f6c494641c4ca99eec7a9f47818526c72789439.tar.xz
Adding new audio output filter layer libaf
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@7569 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libaf')
-rw-r--r--libaf/Makefile38
-rw-r--r--libaf/af.c440
-rw-r--r--libaf/af.h160
-rw-r--r--libaf/af_channels.c171
-rw-r--r--libaf/af_delay.c146
-rw-r--r--libaf/af_dummy.c60
-rw-r--r--libaf/af_format.c291
-rw-r--r--libaf/af_resample.c340
-rw-r--r--libaf/dsp.h22
-rw-r--r--libaf/filter.c257
-rw-r--r--libaf/filter.h65
-rw-r--r--libaf/window.c203
-rw-r--r--libaf/window.h33
13 files changed, 2226 insertions, 0 deletions
diff --git a/libaf/Makefile b/libaf/Makefile
new file mode 100644
index 0000000000..eec59367f8
--- /dev/null
+++ b/libaf/Makefile
@@ -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
diff --git a/libaf/af.c b/libaf/af.c
new file mode 100644
index 0000000000..39b34d8ab5
--- /dev/null
+++ b/libaf/af.c
@@ -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;
+}
diff --git a/libaf/af.h b/libaf/af.h
new file mode 100644
index 0000000000..b0ea7b710a
--- /dev/null
+++ b/libaf/af.h
@@ -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
diff --git a/libaf/af_channels.c b/libaf/af_channels.c
new file mode 100644
index 0000000000..9943e573aa
--- /dev/null
+++ b/libaf/af_channels.c
@@ -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
+};
diff --git a/libaf/af_delay.c b/libaf/af_delay.c
new file mode 100644
index 0000000000..d25e6ed7f2
--- /dev/null
+++ b/libaf/af_delay.c
@@ -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
+};
+
+
diff --git a/libaf/af_dummy.c b/libaf/af_dummy.c
new file mode 100644
index 0000000000..8435b4a626
--- /dev/null
+++ b/libaf/af_dummy.c
@@ -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
+};
diff --git a/libaf/af_format.c b/libaf/af_format.c
new file mode 100644
index 0000000000..d2ee6806b3
--- /dev/null
+++ b/libaf/af_format.c
@@ -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>
+#includ