mirror of
https://github.com/mpv-player/mpv
synced 2024-12-28 06:03:45 +01:00
Adding volume control and moving control() call parameters to a seperate file
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@7746 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
dd84f32ef0
commit
4d6e54d22d
@ -2,7 +2,7 @@ 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
|
||||
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 @@ CFLAGS = $(OPTFLAGS) -I. -Wall
|
||||
$(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)
|
||||
|
||||
|
21
libaf/af.c
21
libaf/af.c
@ -80,9 +80,10 @@ af_instance_t* af_create(af_stream_t* s, char* name)
|
||||
}
|
||||
|
||||
// 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 @@ void af_remove(af_stream_t* s, af_instance_t* af)
|
||||
{
|
||||
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 @@ void af_uninit(af_stream_t* s)
|
||||
-1 if failure */
|
||||
int af_init(af_stream_t* s)
|
||||
{
|
||||
int cfg=SLOW; // configuration type
|
||||
int i=0;
|
||||
|
||||
// Sanity check
|
||||
@ -266,13 +269,11 @@ int af_init(af_stream_t* s)
|
||||
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 @@ int af_init(af_stream_t* s)
|
||||
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
|
||||
|
60
libaf/af.h
60
libaf/af.h
@ -1,3 +1,5 @@
|
||||
#include "control.h"
|
||||
|
||||
#ifndef __aop_h__
|
||||
#define __aop_h__
|
||||
|
||||
@ -53,10 +55,12 @@ typedef struct af_instance_s
|
||||
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{
|
||||
@ -78,43 +82,6 @@ typedef struct af_stream_s
|
||||
af_cfg_t cfg;
|
||||
}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 @@ typedef struct af_stream_s
|
||||
|
||||
|
||||
|
||||
/*********************************************
|
||||
// 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 @@ int af_lencalc(frac_t mul, af_data_t* data);
|
||||
#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 @@ int af_lencalc(frac_t mul, af_data_t* data);
|
||||
#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
|
||||
|
@ -30,9 +30,9 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
|
||||
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
|
||||
|
222
libaf/af_volume.c
Normal file
222
libaf/af_volume.c
Normal file
@ -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
|
||||
};
|
77
libaf/control.h
Normal file
77
libaf/control.h
Normal file
@ -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 */
|
Loading…
Reference in New Issue
Block a user