[Mplayer-cvslog] CVS: main/libaf Makefile,NONE,1.1 af.c,NONE,1.1 af_channels.c,NONE,1.1 af_delay.c,NONE,1.1 af_dummy.c,NONE,1.1 af_format.c,NONE,1.1 af_resample.c,NONE,1.1 filter.c,NONE,1.1 window.c,NONE,1.1 af.h,NONE,1.1 dsp.h,NONE,1.1 filter.h,NONE,1.1 window.h,NONE,1.1

Anders Johansson anders at mplayerhq.hu
Tue Oct 1 08:45:11 CEST 2002


Update of /cvsroot/mplayer/main/libaf
In directory mail:/var/tmp.root/cvs-serv26003/libaf

Added Files:
	Makefile af.c af_channels.c af_delay.c af_dummy.c af_format.c 
	af_resample.c filter.c window.c af.h dsp.h filter.h window.h 
Log Message:
Adding new audio output filter layer libaf

--- NEW FILE ---
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

--- NEW FILE ---
#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;
}

--- NEW FILE ---
/* 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
};

--- NEW FILE ---
/* 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
};



--- NEW FILE ---
/* 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
};

--- NEW FILE ---
/* 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
};

--- NEW FILE ---
/*=============================================================================
//	
//  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 at 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
};


--- NEW FILE ---
/*=============================================================================
//	
//  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 at 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;
}

--- NEW FILE ---
/*=============================================================================
//	
//  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 at 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));
  }
}


--- NEW FILE ---
#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

--- NEW FILE ---
/*=============================================================================
//	
//  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 at 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

--- NEW FILE ---
/*=============================================================================
//	
//  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 at 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

--- NEW FILE ---
/*=============================================================================
//	
//  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 at 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




More information about the MPlayer-cvslog mailing list