view libaf/af_channels.c @ 8401:1b2fc92980d9

Runtime SSE detection for NEtBSD, patch by Nick Hudson <skrll at netbsd.org>
author atmos4
date Sat, 07 Dec 2002 21:04:54 +0000
parents e8832e66babd
children d6f40a06867b
line wrap: on
line source

/* 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 <unistd.h>
#include <inttypes.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:
    af_msg(AF_MSG_ERROR,"[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_COMMAND_LINE:{
    int nch = 0;
    sscanf((char*)arg,"%i",&nch);
    return af->control(af,AF_CONTROL_CHANNELS,&nch);
  }  
  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){
      af_msg(AF_MSG_ERROR,"[channels] The number of output channels must be between 1 and 6. Current value is%i \n",((int*)arg)[0]);
      return AF_ERROR;
    }

    af->data->nch=((int*)arg)[0]; 
    af_msg(AF_MSG_VERBOSE,"[channels] Changing number of channels to %i\n",af->data->nch);
    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,(c->len*af->mul.n)/af->mul.d);
  
  // Special case always output L & R
  if(c->nch == 1){
    copy(c->audio,l->audio,1,0,l->nch,0,c->len,c->bps);
    copy(c->audio,l->audio,1,0,l->nch,1,c->len,c->bps);
  }
  else{
    int i;
    if(l->nch < c->nch){ 
      for(i=0;i<l->nch;i++) // Truncates R if l->nch == 1 not good need mixing
	copy(c->audio,l->audio,c->nch,i,l->nch,i,c->len,c->bps);	
    }
    else{
      for(i=0;i<c->nch;i++)
	copy(c->audio,l->audio,c->nch,i,l->nch,i,c->len,c->bps);	
    }
  }
  
  // Set output data
  c->audio = l->audio;
  c->len   = (c->len*af->mul.n)/af->mul.d;
  c->nch   = l->nch;

  return c;
}

// Allocate memory and set function pointers
static int open(af_instance_t* af){
  af->control=control;
  af->uninit=uninit;
  af->play=play;
  af->mul.n=1;
  af->mul.d=1;
  af->data=calloc(1,sizeof(af_data_t));
  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",
  "",
  AF_FLAGS_REENTRANT,
  open
};