changeset 7745:1d3a3dc1f488

Adding volume control and moving control() call parameters to a seperate file
author anders
date Wed, 16 Oct 2002 01:49:40 +0000
parents 6d41f5e905e2
children 15ce89ba92cf
files libaf/Makefile libaf/af.c libaf/af.h libaf/af_delay.c libaf/af_volume.c libaf/control.h
diffstat 6 files changed, 333 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/libaf/Makefile	Tue Oct 15 13:51:46 2002 +0000
+++ b/libaf/Makefile	Wed Oct 16 01:49:40 2002 +0000
@@ -2,7 +2,7 @@
 
 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
+SRCS=af.c af_dummy.c af_delay.c af_channels.c af_format.c af_resample.c window.c filter.c af_volume.c
 
 OBJS=$(SRCS:.c=.o)
 
@@ -15,7 +15,7 @@
 $(LIBNAME):     $(OBJS) Makefile
 	$(AR) r $(LIBNAME) $(OBJS)
 
-$(OBJS):af.h dsp.h filter.h window.h
+$(OBJS):af.h control.h dsp.h filter.h window.h
 
 all:    $(LIBNAME)
 
--- a/libaf/af.c	Tue Oct 15 13:51:46 2002 +0000
+++ b/libaf/af.c	Wed Oct 16 01:49:40 2002 +0000
@@ -80,9 +80,10 @@
   }
 
   // Initialize the new filter
-  if(AF_OK==new->info->open(new)) 
+  if(AF_OK == new->info->open(new) && 
+     AF_ERROR < new->control(new,AF_CONTROL_POST_CREATE,&s->cfg))
     return new;
-
+  
   free(new);
   mp_msg(MSGT_AFILTER,MSGL_ERR,"Couldn't create audio filter '%s'\n",name);  
   return NULL;
@@ -141,6 +142,9 @@
 {
   if(!af) return;
 
+  // Notify filter before changing anything
+  af->control(af,AF_CONTROL_PRE_DESTROY,0);
+
   // Detach pointers
   if(af->prev)
     af->prev->next=af->next;
@@ -255,7 +259,6 @@
    -1 if failure */
 int af_init(af_stream_t* s)
 {
-  int cfg=SLOW;  // configuration type
   int i=0;
 
   // Sanity check
@@ -266,13 +269,11 @@
   s->input.len    = s->output.len    = 0;
 
   // Figure out how fast the machine is
-  if(s->cfg.force)
-    cfg=s->cfg.force;
-  else{
+  if(AF_INIT_AUTO == (AF_INIT_TYPE_MASK & s->cfg.force)){
 #    if defined(HAVE_SSE) || defined(HAVE_3DNOWEX)
-      cfg=FAST;
+    s->cfg.force = (s->cfg.force & ~AF_INIT_TYPE_MASK) | AF_INIT_FAST;
 #    else
-      cfg=SLOW;
+    s->cfg.force = (s->cfg.force & ~AF_INIT_TYPE_MASK) | AF_INIT_SLOW;
 #    endif
   }
 
@@ -296,12 +297,12 @@
     return -1;
 
   // Check output format
-  if(cfg!=FORCE){
+  if((AF_INIT_TYPE_MASK & s->cfg.force) != AF_INIT_FORCE){
     af_instance_t* af = NULL; // New filter
     // Check output frequency if not OK fix with resample
     if(s->last->data->rate!=s->output.rate){
       if(NULL==(af=af_get(s,"resample"))){
-	if(cfg==SLOW){
+	if((AF_INIT_TYPE_MASK & s->cfg.force) == AF_INIT_SLOW){
 	  if(!strcmp(s->first->info->name,"format"))
 	    af = af_append(s,s->first,"resample");
 	  else
--- a/libaf/af.h	Tue Oct 15 13:51:46 2002 +0000
+++ b/libaf/af.h	Wed Oct 16 01:49:40 2002 +0000
@@ -1,3 +1,5 @@
+#include "control.h"
+
 #ifndef __aop_h__
 #define __aop_h__
 
@@ -53,10 +55,12 @@
 		 the length of the buffer. */
 }af_instance_t;
 
-// Initialization types
-#define SLOW  1
-#define FAST  2
-#define FORCE 3
+// Initialization flags
+#define AF_INIT_AUTO		0x00000000
+#define AF_INIT_SLOW		0x00000001
+#define AF_INIT_FAST		0x00000002
+#define AF_INIT_FORCE	  	0x00000003
+#define AF_INIT_TYPE_MASK 	0x00000003
 
 // Configuration switches
 typedef struct af_cfg_s{
@@ -79,43 +83,6 @@
 }af_stream_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
 */
 
@@ -129,7 +96,9 @@
 
 
 
+/*********************************************
 // Export functions
+*/
 
 /* Initialize the stream "s". This function creates a new fileterlist
    if nessesary according to the values set in input and output. Input
@@ -201,6 +170,7 @@
 #define RESIZE_LOCAL_BUFFER(a,d)\
 ((a->data->len < af_lencalc(a->mul,d))?af_resize_local_buffer(a,d):AF_OK)
 
+/* Some other useful macro definitions*/
 #ifndef min
 #define min(a,b)(((a)>(b))?(b):(a))
 #endif
@@ -209,4 +179,12 @@
 #define max(a,b)(((a)>(b))?(a):(b))
 #endif
 
+#ifndef clamp
+#define clamp(a,min,max) (((a)>(max))?(max):(((a)<(min))?(min):(a)))
 #endif
+
+#ifndef sign
+#define sign(a) (((x)>0)?(1):(-1)) 
+#endif
+
+#endif
--- a/libaf/af_delay.c	Tue Oct 15 13:51:46 2002 +0000
+++ b/libaf/af_delay.c	Wed Oct 16 01:49:40 2002 +0000
@@ -30,9 +30,9 @@
     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);
+    return af->control(af,AF_CONTROL_DELAY_SET_LEN,&((af_delay_t*)af->setup)->tlen);
   }
-  case AF_CONTROL_SET_DELAY_LEN:{
+  case AF_CONTROL_DELAY_SET_LEN:{
     af_delay_t* s  = (af_delay_t*)af->setup;
     void*       bt = s->buf; // Old buffer
     int         lt = s->len; // Old len
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/af_volume.c	Wed Oct 16 01:49:40 2002 +0000
@@ -0,0 +1,222 @@
+/* This audio filter changes the volume of the sound, and can be used
+   when the mixer doesn't support the PCM channel. It can handel
+   between 1 and 6 channels. The volume can be adjusted between -60dB
+   to +10dB and is set on a per channels basis. The volume can be
+   written ad read by AF_CONTROL_VOLUME_SET and AF_CONTROL_VOLUME_GET
+   respectivly.
+
+   The plugin has support for softclipping, it is enabled by
+   AF_CONTROL_VOLUME_SOFTCLIPP. It has also a probing feature which
+   can be used to measure the power in the audio stream, both an
+   instantanious value and the maximum value can be probed. The
+   probing is enable by AF_CONTROL_VOLUME_PROBE_ON_OFF and is done on a
+   per channel basis. The result from the probing is obtained using
+   AF_CONTROL_VOLUME_PROBE_GET and AF_CONTROL_VOLUME_PROBE_GET_MAX. The
+   probed values are calculated in dB. The control of the volume can
+   be turned off by the AF_CONTROL_VOLUME_ON_OFF switch.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include "../config.h"
+#include "../mp_msg.h"
+
+#include "af.h"
+
+// Some limits
+#define MIN_S16 -32650
+#define MAX_S16  32650
+
+#define MAX_VOL +10.0
+#define MIN_VOL	-60.0
+
+// Number of channels
+#define NCH 6
+
+#include "../libao2/afmt.h"
+
+
+// Data for specific instances of this filter
+typedef struct af_volume_s
+{
+  double volume[NCH];	// Volume for each channel
+  double power[NCH];	// Instantaneous power in each channel
+  double maxpower[NCH];	// Maximum power in each channel
+  double alpha;		// Forgetting factor for power estimate
+  int softclip;		// Soft clippng on/off
+  int probe;		// Probing on/off
+  int onoff;		// Volume control on/off
+}af_volume_t;
+
+/* Convert to gain value from dB. Returns AF_OK if of and AF_ERROR if
+   fail */
+inline int from_dB(double* in, double* out) 
+{
+  int i = 0; 
+  // Sanity check
+  if(!in || !out) 
+    return AF_ERROR;
+
+  for(i=0;i<NCH;i++) 
+    out[i]=pow(10.0,clamp(in[i],MIN_VOL,MAX_VOL)/10.0);
+  return AF_OK;
+}
+
+/* Convert from gain value to dB. Returns AF_OK if of and AF_ERROR if
+   fail */
+inline int to_dB(double* in, double* out) 
+{
+  int i = 0; 
+  // Sanity check
+  if(!in || !out) 
+    return AF_ERROR;
+
+  for(i=0;i<NCH;i++) 
+    out[i]=10.0*log10(clamp(in[i],MIN_VOL,MAX_VOL));
+  return AF_OK;
+}
+
+// Initialization and runtime control
+static int control(struct af_instance_s* af, int cmd, void* arg)
+{
+  af_volume_t* s   = (af_volume_t*)af->setup; 
+
+  switch(cmd){
+  case AF_CONTROL_REINIT:
+    // Sanity check
+    if(!arg) return AF_ERROR;
+    
+    af->data->rate   = ((af_data_t*)arg)->rate;
+    af->data->nch    = ((af_data_t*)arg)->nch;
+    af->data->format = AFMT_S16_LE;
+    af->data->bps    = 2;
+    
+    // Time constant set to 0.1s
+    s->alpha = (1.0/0.2)/(2.0*M_PI*(double)((af_data_t*)arg)->rate); 
+
+    // Only AFMT_S16_LE is supported for now
+    if(af->data->format != ((af_data_t*)arg)->format || 
+       af->data->bps != ((af_data_t*)arg)->bps)
+      return AF_FALSE;
+    return AF_OK;
+  case AF_CONTROL_VOLUME_SET:
+    return from_dB((double*)arg,s->volume);
+  case AF_CONTROL_VOLUME_GET:
+    return to_dB(s->volume,(double*)arg);
+  case AF_CONTROL_VOLUME_PROBE_GET:
+    return to_dB(s->power,(double*)arg);
+  case AF_CONTROL_VOLUME_PROBE_GET_MAX:
+    return to_dB(s->maxpower,(double*)arg);
+  case AF_CONTROL_VOLUME_SOFTCLIP:
+    s->softclip = (int)arg;
+    return AF_OK;
+  case AF_CONTROL_VOLUME_PROBE_ON_OFF:
+    s->probe = (int)arg;
+    return AF_OK;
+  case AF_CONTROL_VOLUME_ON_OFF:
+    s->onoff = (int)arg;
+    return AF_OK;
+  }
+  return AF_UNKNOWN;
+}
+
+// Deallocate memory 
+static void uninit(struct af_instance_s* af)
+{
+  if(af->data)
+    free(af->data);
+  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_volume_t*   s = (af_volume_t*)af->setup; 	// Setup for this instance
+  int16_t*       a = (int16_t*)c->audio;	// Audio data
+  int          len = c->len/2;			// Number of samples
+  int           ch = 0;				// Channel counter
+  register int nch = c->nch;			// Number of channels	
+  register int   i = 0;
+  
+  // Probe the data stream 
+  if(s->probe){
+    for(ch = 0; ch < nch ; ch++){
+      double alpha  = s->alpha;
+      double beta   = 1 - alpha;
+      double pow    = s->power[ch];
+      double maxpow = s->maxpower[ch];
+      register double t = 0;
+      for(i=ch;i<len;i+=nch){
+	t = ((double)a[i])/32768.0;
+	t *= t;
+	// Check maximum power value
+	if(t>maxpow) 
+	  maxpow=t;
+	// Power estimate made using first order AR model
+	if(t>pow)
+	  pow=t;
+	else
+	  pow = beta*pow+alpha*t;
+      }
+      s->power[ch]    = pow;
+      s->maxpower[ch] = maxpow;
+    }
+  }
+
+  // Change the volume.
+  if(s->onoff){
+    register int sc  = s->softclip;
+    for(ch = 0; ch < nch ; ch++){
+      register int vol = (int)(255.0 * s->volume[ch]); 
+      for(i=ch;i<len;i+=nch){
+	register int x;
+	x=(a[i] * vol) >> 8;
+	if(sc){
+	  int64_t t=x*x;
+	  t=(t*x) >> 30;
+	  x = (3*x - (int)t) >> 1;
+	}
+	a[i]=clamp(x,MIN_S16,MAX_S16);
+      }
+    }
+  }
+
+  return c;
+}
+
+// Allocate memory and set function pointers
+static int open(af_instance_t* af){
+  int i = 0;
+  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_volume_t));
+  if(af->data == NULL || af->setup == NULL)
+    return AF_ERROR;
+  // Enable volume control and set initial volume to 0.1
+  ((af_volume_t*)af->setup)->onoff = 1;
+  for(i=0;i<NCH;i++)
+    ((af_volume_t*)af->setup)->volume[i]=0.1;
+
+  return AF_OK;
+}
+
+// Description of this filter
+af_info_t af_info_volume = {
+    "Volume control audio filter",
+    "volume",
+    "Anders",
+    "",
+    AF_FLAGS_NOT_REENTRANT,
+    open
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libaf/control.h	Wed Oct 16 01:49:40 2002 +0000
@@ -0,0 +1,77 @@
+#ifndef __af_control_h
+#define __af_control_h
+
+/*********************************************
+// 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  		01 + AF_CONTROL_MANDATORY_BASE
+
+// OPTIONAL CALLS
+
+/* Called just after creation with the af_cfg for the stream in which
+   the filter resides as input parameter this call can be used by the
+   filter to initialize itself using commandline parameters */
+#define AF_CONTROL_POST_CREATE 		1 + AF_CONTROL_OPTIONAL_BASE
+
+// Called just before destruction of a filter
+#define AF_CONTROL_PRE_DESTROY 		2 + AF_CONTROL_OPTIONAL_BASE
+
+
+// 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_DELAY_SET_LEN	4 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Volume 
+
+// Set volume level, arg is a float* with the volume for all the channels
+#define AF_CONTROL_VOLUME_SET		5 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+/* Get volume level for all channels, arg is a float* that will
+   contain the volume for all the channels */
+#define AF_CONTROL_VOLUME_GET		6 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Turn volume control on and off, arg is binary
+#define AF_CONTROL_VOLUME_ON_OFF	7 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Turn soft clipping of the volume on and off, arg is binary
+#define AF_CONTROL_VOLUME_SOFTCLIP	8 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Get the probed power level for all channels, arg is a float* 
+#define AF_CONTROL_VOLUME_PROBE_GET	9 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Get the maximum probed power level for all channels, arg is a float* 
+#define AF_CONTROL_VOLUME_PROBE_GET_MAX	10 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Turn probing on and off, arg is binary
+#define AF_CONTROL_VOLUME_PROBE_ON_OFF 	11 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+#endif /*__af_control_h */