1
0
mirror of https://github.com/mpv-player/mpv synced 2025-04-11 04:01:31 +00:00

af: remove deprecated audio filters

These couldn't be relicensed, and won't survive the LGPL transition. The
other existing filters are mostly LGPL (except libaf glue code).

This remove the deprecated pan option. I guess it could be restored by
inserting a libavfilter filter (if there's one), but for now let it be
gone.

This temporarily breaks volume control (and things related to it, like
replaygain).
This commit is contained in:
wm4 2017-11-29 20:13:28 +01:00
parent 23d9dc5457
commit 3d27a0792b
13 changed files with 1 additions and 1153 deletions

View File

@ -91,81 +91,6 @@ Available filters are:
Select the libavcodec encoder used. Currently, this should be an AC-3
encoder, and using another codec will fail horribly.
``equalizer=g1:g2:g3:...:g10``
10 octave band graphic equalizer, implemented using 10 IIR band-pass
filters. This means that it works regardless of what type of audio is
being played back. The center frequencies for the 10 bands are:
=== ==========
No. frequency
=== ==========
0 31.25 Hz
1 62.50 Hz
2 125.00 Hz
3 250.00 Hz
4 500.00 Hz
5 1.00 kHz
6 2.00 kHz
7 4.00 kHz
8 8.00 kHz
9 16.00 kHz
=== ==========
If the sample rate of the sound being played is lower than the center
frequency for a frequency band, then that band will be disabled. A known
bug with this filter is that the characteristics for the uppermost band
are not completely symmetric if the sample rate is close to the center
frequency of that band. This problem can be worked around by upsampling
the sound using a resampling filter before it reaches this filter.
``<g1>:<g2>:<g3>:...:<g10>``
floating point numbers representing the gain in dB for each frequency
band (-12-12)
.. admonition:: Example
``mpv --af=equalizer=11:11:10:5:0:-12:0:5:12:12 media.avi``
Would amplify the sound in the upper and lower frequency region
while canceling it almost completely around 1 kHz.
``channels=nch[:routes]``
Can be used for adding, removing, routing and copying audio channels. If
only ``<nch>`` is given, the default routing is used. It works as follows:
If the number of output channels is greater than the number of input
channels, empty channels are inserted (except when mixing from mono to
stereo; then the mono channel is duplicated). If the number of output
channels is less than the number of input channels, the exceeding
channels are truncated.
``<nch>``
number of output channels (1-8)
``<routes>``
List of ``,`` separated routes, in the form ``from1-to1,from2-to2,...``.
Each pair defines where to route each channel. There can be at most
8 routes. Without this argument, the default routing is used. Since
``,`` is also used to separate filters, you must quote this argument
with ``[...]`` or similar.
.. admonition:: Examples
``mpv --af=channels=4:[0-1,1-0,2-2,3-3] media.avi``
Would change the number of channels to 4 and set up 4 routes that
swap channel 0 and channel 1 and leave channel 2 and 3 intact.
Observe that if media containing two channels were played back,
channels 2 and 3 would contain silence but 0 and 1 would still be
swapped.
``mpv --af=channels=6:[0-0,0-1,0-2,0-3] media.avi``
Would change the number of channels to 6 and set up 4 routes that
copy channel 0 to channels 0 to 3. Channel 4 and 5 will contain
silence.
.. note::
You should probably not use this filter. If you want to change the
output channel layout, try the ``format`` filter, which can make mpv
automatically up- and downmix standard channel layouts.
``format=format:srate:channels:out-format:out-srate:out-channels``
Does not do any format conversion itself. Rather, it may cause the
filter system to insert necessary conversion filters before or after this
@ -205,107 +130,6 @@ Available filters are:
used to do conversion itself, unlike this one which lets the filter system
handle the conversion.
``volume[=<volumedb>[:...]]``
Implements software volume control. Use this filter with caution since it
can reduce the signal to noise ratio of the sound. In most cases it is
best to use the *Master* volume control of your sound card or the volume
knob on your amplifier.
*WARNING*: This filter is deprecated. Use the top-level options like
``--volume`` and ``--replaygain...`` instead.
*NOTE*: This filter is not reentrant and can therefore only be enabled
once for every audio stream.
``<volumedb>``
Sets the desired gain in dB for all channels in the stream from -200 dB
to +60 dB, where -200 dB mutes the sound completely and +60 dB equals a
gain of 1000 (default: 0).
``replaygain-track``
Adjust volume gain according to the track-gain replaygain value stored
in the file metadata.
``replaygain-album``
Like replaygain-track, but using the album-gain value instead.
``replaygain-preamp``
Pre-amplification gain in dB to apply to the selected replaygain gain
(default: 0).
``replaygain-clip=yes|no``
Prevent clipping caused by replaygain by automatically lowering the
gain (default). Use ``replaygain-clip=no`` to disable this.
``replaygain-fallback``
Gain in dB to apply if the file has no replay gain tags. This option
is always applied if the replaygain logic is somehow inactive. If this
is applied, no other replaygain options are applied.
``softclip``
Turns soft clipping on. Soft-clipping can make the
sound more smooth if very high volume levels are used. Enable this
option if the dynamic range of the loudspeakers is very low.
*WARNING*: This feature creates distortion and should be considered a
last resort.
``s16``
Force S16 sample format if set. Lower quality, but might be faster
in some situations.
``detach``
Remove the filter if the volume is not changed at audio filter config
time. Useful with replaygain: if the current file has no replaygain
tags, then the filter will be removed if this option is enabled.
(If ``--softvol=yes`` is used and the player volume controls are used
during playback, a different volume filter will be inserted.)
.. admonition:: Example
``mpv --af=volume=10.1 media.avi``
Would amplify the sound by 10.1 dB and hard-clip if the sound level
is too high.
``pan=n:[<matrix>]``
Mixes channels arbitrarily. Basically a combination of the volume and the
channels filter that can be used to down-mix many channels to only a few,
e.g. stereo to mono, or vary the "width" of the center speaker in a
surround sound system. This filter is hard to use, and will require some
tinkering before the desired result is obtained. The number of options for
this filter depends on the number of output channels. An example how to
downmix a six-channel file to two channels with this filter can be found
in the examples section near the end.
``<n>``
Number of output channels (1-8).
``<matrix>``
A list of values ``[L00,L01,L02,...,L10,L11,L12,...,Ln0,Ln1,Ln2,...]``,
where each element ``Lij`` means how much of input channel i is mixed
into output channel j (range 0-1). So in principle you first have n
numbers saying what to do with the first input channel, then n numbers
that act on the second input channel etc. If you do not specify any
numbers for some input channels, 0 is assumed.
Note that the values are separated by ``,``, which is already used
by the option parser to separate filters. This is why you must quote
the value list with ``[...]`` or similar.
.. admonition:: Examples
``mpv --af=pan=1:[0.5,0.5] media.avi``
Would downmix from stereo to mono.
``mpv --af=pan=3:[1,0,0.5,0,1,0.5] media.avi``
Would give 3 channel output leaving channels 0 and 1 intact, and mix
channels 0 and 1 into output channel 2 (which could be sent to a
subwoofer for example).
.. note::
If you just want to force remixing to a certain output channel layout,
it is easier to use the ``format`` filter. For example,
``mpv '--af=format=channels=5.1' '--audio-channels=5.1'`` would always force
remixing audio to 5.1 and output it like this.
This filter supports the following ``af-command`` commands:
``set-matrix``
Set the ``<matrix>`` argument dynamically. This can be used to change
the mixing matrix at runtime, without reinitializing the entire filter
chain.
``scaletempo[=option1:option2:...]``
Scales audio tempo without altering pitch, optionally synced to playback
speed (default).

View File

@ -1289,14 +1289,6 @@ Audio
is always applied if the replaygain logic is somehow inactive. If this
is applied, no other replaygain options are applied.
``--balance=<value>``
How much left/right channels contribute to the audio. (The implementation
of this feature is rather odd. It doesn't change the volumes of each
channel, but instead sets up a pan matrix to mix the left and right
channels.)
Deprecated.
``--audio-delay=<sec>``
Audio delay in seconds (positive or negative float value). Positive values
delay the audio, and negative values delay the video.

View File

@ -31,25 +31,16 @@
#include "af.h"
// Static list of filters
extern const struct af_info af_info_channels;
extern const struct af_info af_info_format;
extern const struct af_info af_info_volume;
extern const struct af_info af_info_equalizer;
extern const struct af_info af_info_pan;
extern const struct af_info af_info_lavcac3enc;
extern const struct af_info af_info_lavrresample;
extern const struct af_info af_info_scaletempo;
extern const struct af_info af_info_bs2b;
extern const struct af_info af_info_lavfi;
extern const struct af_info af_info_lavfi_bridge;
extern const struct af_info af_info_rubberband;
static const struct af_info *const filter_list[] = {
&af_info_channels,
&af_info_format,
&af_info_volume,
&af_info_equalizer,
&af_info_pan,
&af_info_lavcac3enc,
&af_info_lavrresample,
#if HAVE_RUBBERBAND

View File

@ -120,11 +120,6 @@ struct af_stream {
enum af_control {
AF_CONTROL_REINIT = 1,
AF_CONTROL_RESET,
AF_CONTROL_SET_VOLUME,
AF_CONTROL_SET_PAN_LEVEL,
AF_CONTROL_SET_PAN_NOUT,
AF_CONTROL_SET_PAN_BALANCE,
AF_CONTROL_GET_PAN_BALANCE,
AF_CONTROL_SET_PLAYBACK_SPEED,
AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE,
AF_CONTROL_GET_METADATA,

View File

@ -1,255 +0,0 @@
/*
* 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.
*
* Original author: Anders
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "common/common.h"
#include "af.h"
#define FR 0
#define TO 1
typedef struct af_channels_s{
int route[AF_NCH][2];
int nch, nr;
int router;
char *routes;
}af_channels_t;
// Local function for copying data
static void copy(struct af_instance *af, 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 3:{
int8_t* tin = (int8_t*)in;
int8_t* tout = (int8_t*)out;
tin += 3 * inos;
tout += 3 * outos;
len = len / ( 3 * ins);
while (len--) {
tout[0] = tin[0];
tout[1] = tin[1];
tout[2] = tin[2];
tin += 3 * ins;
tout += 3 * 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_ERR(af, "Unsupported number of bytes/sample: %i"
" please report this error on the MPlayer mailing list. \n",bps);
}
}
// Make sure the routes are sane
static int check_routes(struct af_instance *af, int nin, int nout)
{
af_channels_t* s = af->priv;
int i;
if((s->nr < 1) || (s->nr > AF_NCH)){
MP_ERR(af, "The number of routing pairs must be"
" between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
return AF_ERROR;
}
for(i=0;i<s->nr;i++){
if((s->route[i][FR] >= nin) || (s->route[i][TO] >= nout)){
MP_ERR(af, "Invalid routing in pair nr. %i.\n", i);
return AF_ERROR;
}
}
return AF_OK;
}
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
af_channels_t* s = af->priv;
switch(cmd){
case AF_CONTROL_REINIT: ;
struct mp_chmap chmap;
mp_chmap_set_unknown(&chmap, s->nch);
mp_audio_set_channels(af->data, &chmap);
// Set default channel assignment
if(!s->router){
int i;
// Make sure this filter isn't redundant
if(af->data->nch == ((struct mp_audio*)arg)->nch)
return AF_DETACH;
// If mono: fake stereo
if(((struct mp_audio*)arg)->nch == 1){
s->nr = MPMIN(af->data->nch,2);
for(i=0;i<s->nr;i++){
s->route[i][FR] = 0;
s->route[i][TO] = i;
}
}
else{
s->nr = MPMIN(af->data->nch, ((struct mp_audio*)arg)->nch);
for(i=0;i<s->nr;i++){
s->route[i][FR] = i;
s->route[i][TO] = i;
}
}
}
af->data->rate = ((struct mp_audio*)arg)->rate;
mp_audio_force_interleaved_format((struct mp_audio*)arg);
mp_audio_set_format(af->data, ((struct mp_audio*)arg)->format);
return check_routes(af,((struct mp_audio*)arg)->nch,af->data->nch);
}
return AF_UNKNOWN;
}
static int filter_frame(struct af_instance *af, struct mp_audio *c)
{
af_channels_t* s = af->priv;
int i;
if (!c)
return 0;
struct mp_audio *l = mp_audio_pool_get(af->out_pool, &af->fmt_out, c->samples);
if (!l) {
talloc_free(c);
return -1;
}
mp_audio_copy_attributes(l, c);
// Reset unused channels
memset(l->planes[0],0,mp_audio_psize(c) / c->nch * l->nch);
if(AF_OK == check_routes(af,c->nch,l->nch))
for(i=0;i<s->nr;i++)
copy(af, c->planes[0],l->planes[0],c->nch,s->route[i][FR],
l->nch,s->route[i][TO],mp_audio_psize(c),c->bps);
talloc_free(c);
af_add_output_frame(af, l);
return 0;
}
// Allocate memory and set function pointers
static int af_open(struct af_instance* af){
af->control=control;
af->filter_frame = filter_frame;
af_channels_t *s = af->priv;
MP_WARN(af, "This filter is deprecated (no replacement).\n");
// If router scan commandline for routing pairs
if(s->routes && s->routes[0]){
char* cp = s->routes;
int ch = 0;
// Scan for pairs on commandline
do {
int n = 0;
if (ch >= AF_NCH) {
MP_FATAL(af, "Can't have more than %d routes.\n", AF_NCH);
return AF_ERROR;
}
sscanf(cp, "%i-%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n);
MP_VERBOSE(af, "Routing from channel %i to"
" channel %i\n",s->route[ch][FR],s->route[ch][TO]);
cp = &cp[n];
ch++;
} while(*cp == ',' && *(cp++));
s->nr = ch;
if (s->nr > 0)
s->router = 1;
}
return AF_OK;
}
#define OPT_BASE_STRUCT af_channels_t
const struct af_info af_info_channels = {
.info = "Insert or remove channels",
.name = "channels",
.open = af_open,
.priv_size = sizeof(af_channels_t),
.options = (const struct m_option[]) {
OPT_INTRANGE("nch", nch, 0, 1, AF_NCH, OPTDEF_INT(2)),
OPT_STRING("routes", routes, 0),
{0}
},
};

View File

@ -1,215 +0,0 @@
/*
* Equalizer filter, implementation of a 10 band time domain graphic
* equalizer using IIR filters. The IIR filters are implemented using a
* Direct Form II approach, but has been modified (b1 == 0 always) to
* save computation.
*
* Copyright (C) 2001 Anders Johansson ajh@atri.curtin.edu.au
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <math.h>
#include "common/common.h"
#include "af.h"
#define L 2 // Storage for filter taps
#define KM 10 // Max number of bands
#define Q 1.2247449 /* Q value for band-pass filters 1.2247=(3/2)^(1/2)
gives 4dB suppression @ Fc*2 and Fc/2 */
/* Center frequencies for band-pass filters
The different frequency bands are:
nr. center frequency
0 31.25 Hz
1 62.50 Hz
2 125.0 Hz
3 250.0 Hz
4 500.0 Hz
5 1.000 kHz
6 2.000 kHz
7 4.000 kHz
8 8.000 kHz
9 16.00 kHz
*/
#define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000}
// Maximum and minimum gain for the bands
#define G_MAX +12.0
#define G_MIN -12.0
// Data for specific instances of this filter
typedef struct af_equalizer_s
{
float a[KM][L]; // A weights
float b[KM][L]; // B weights
float wq[AF_NCH][KM][L]; // Circular buffer for W data
float g[AF_NCH][KM]; // Gain factor for each channel and band
int K; // Number of used eq bands
int channels; // Number of channels
float gain_factor; // applied at output to avoid clipping
double p[KM];
} af_equalizer_t;
// 2nd order Band-pass Filter design
static void bp2(float* a, float* b, float fc, float q){
double th= 2.0 * M_PI * fc;
double C = (1.0 - tan(th*q/2.0))/(1.0 + tan(th*q/2.0));
a[0] = (1.0 + C) * cos(th);
a[1] = -1 * C;
b[0] = (1.0 - C)/2.0;
b[1] = -1.0050;
}
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
af_equalizer_t* s = (af_equalizer_t*)af->priv;
switch(cmd){
case AF_CONTROL_REINIT:{
int k =0, i =0;
float F[KM] = CF;
s->gain_factor=0.0;
// Sanity check
if(!arg) return AF_ERROR;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
// Calculate number of active filters
s->K=KM;
while(F[s->K-1] > (float)af->data->rate/2.2)
s->K--;
if(s->K != KM)
MP_INFO(af, "Limiting the number of filters to"
" %i due to low sample rate.\n",s->K);
// Generate filter taps
for(k=0;k<s->K;k++)
bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q);
// Calculate how much this plugin adds to the overall time delay
af->delay = 2.0 / (double)af->data->rate;
// Calculate gain factor to prevent clipping at output
for(k=0;k<AF_NCH;k++)
{
for(i=0;i<KM;i++)
{
if(s->gain_factor < s->g[k][i]) s->gain_factor=s->g[k][i];
}
}
s->gain_factor=log10(s->gain_factor + 1.0) * 20.0;
if(s->gain_factor > 0.0)
{
s->gain_factor=0.1+(s->gain_factor/12.0);
}else{
s->gain_factor=1;
}
return af_test_output(af,arg);
}
}
return AF_UNKNOWN;
}
static int filter(struct af_instance* af, struct mp_audio* data)
{
struct mp_audio* c = data; // Current working data
if (!c)
return 0;
af_equalizer_t* s = (af_equalizer_t*)af->priv; // Setup
uint32_t ci = af->data->nch; // Index for channels
uint32_t nch = af->data->nch; // Number of channels
if (af_make_writeable(af, data) < 0) {
talloc_free(data);
return -1;
}
while(ci--){
float* g = s->g[ci]; // Gain factor
float* in = ((float*)c->planes[0])+ci;
float* out = ((float*)c->planes[0])+ci;
float* end = in + c->samples*c->nch; // Block loop end
while(in < end){
register int k = 0; // Frequency band index
register float yt = *in; // Current input sample
in+=nch;
// Run the filters
for(;k<s->K;k++){
// Pointer to circular buffer wq
register float* wq = s->wq[ci][k];
// Calculate output from AR part of current filter
register float w=yt*s->b[k][0] + wq[0]*s->a[k][0] + wq[1]*s->a[k][1];
// Calculate output form MA part of current filter
yt+=(w + wq[1]*s->b[k][1])*g[k];
// Update circular buffer
wq[1] = wq[0];
wq[0] = w;
}
// Calculate output
*out=yt*s->gain_factor;
out+=nch;
}
}
af_add_output_frame(af, data);
return 0;
}
// Allocate memory and set function pointers
static int af_open(struct af_instance* af){
MP_WARN(af, "This filter is deprecated. Use 'anequalizer' or 'firequalizer' instead.\n");
af->control=control;
af->filter_frame = filter;
af_equalizer_t *priv = af->priv;
for(int i=0;i<AF_NCH;i++){
for(int j=0;j<KM;j++){
priv->g[i][j] = pow(10.0,MPCLAMP(priv->p[j],G_MIN,G_MAX)/20.0)-1.0;
}
}
return AF_OK;
}
#define OPT_BASE_STRUCT af_equalizer_t
const struct af_info af_info_equalizer = {
.info = "Equalizer audio filter",
.name = "equalizer",
.open = af_open,
.priv_size = sizeof(af_equalizer_t),
.options = (const struct m_option[]) {
#define BAND(n) OPT_DOUBLE("e" #n, p[n], 0)
BAND(0), BAND(1), BAND(2), BAND(3), BAND(4),
BAND(5), BAND(6), BAND(7), BAND(8), BAND(9),
{0}
},
};

View File

@ -1,206 +0,0 @@
/*
* Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include "common/common.h"
#include "af.h"
// Data for specific instances of this filter
typedef struct af_pan_s {
int nch; // Number of output channels; zero means same as input
float level[AF_NCH][AF_NCH]; // Gain level for each channel
char *matrixstr;
} af_pan_t;
static void set_channels(struct mp_audio *mpa, int num)
{
struct mp_chmap map;
// "unknown" channel layouts make it easier to pass through audio data,
// without triggering remixing.
mp_chmap_set_unknown(&map, num);
mp_audio_set_channels(mpa, &map);
}
static void parse_matrix(struct af_instance *af, const char *cp)
{
af_pan_t *s = af->priv;
int j = 0, k = 0, n;
while (*cp && k < AF_NCH) {
sscanf(cp, "%f%n" , &s->level[j][k], &n);
MP_VERBOSE(af, "Pan level from channel %i to"
" channel %i = %f\n", k, j, s->level[j][k]);
cp = &cp[n];
j++;
if (j >= s->nch) {
j = 0;
k++;
}
if (*cp != ',')
break;
cp++;
}
}
// Initialization and runtime control
static int control(struct af_instance *af, int cmd, void *arg)
{
af_pan_t* s = af->priv;
switch(cmd){
case AF_CONTROL_REINIT:
// Sanity check
if (!arg)
return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
set_channels(af->data, s->nch ? s->nch : ((struct mp_audio*)arg)->nch);
if ((af->data->format != ((struct mp_audio*)arg)->format) ||
(af->data->bps != ((struct mp_audio*)arg)->bps)) {
mp_audio_set_format((struct mp_audio*)arg, af->data->format);
return AF_FALSE;
}
return AF_OK;
case AF_CONTROL_SET_PAN_LEVEL: {
int i;
int ch = ((af_control_ext_t*)arg)->ch;
float *level = ((af_control_ext_t*)arg)->arg;
if (ch >= AF_NCH)
return AF_FALSE;
for (i = 0; i < AF_NCH; i++)
s->level[ch][i] = level[i];
return AF_OK;
}
case AF_CONTROL_SET_PAN_NOUT:
// Reinit must be called after this function has been called
// Sanity check
if (((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH) {
MP_ERR(af, "The number of output channels must be"
" between 1 and %i. Current value is %i\n",
AF_NCH, ((int*)arg)[0]);
return AF_ERROR;
}
s->nch = ((int*)arg)[0];
return AF_OK;
case AF_CONTROL_SET_PAN_BALANCE: {
float val = *(float*)arg;
if (s->nch)
return AF_ERROR;
if (af->data->nch >= 2) {
s->level[0][0] = MPMIN(1.f, 1.f - val);
s->level[0][1] = MPMAX(0.f, val);
s->level[1][0] = MPMAX(0.f, -val);
s->level[1][1] = MPMIN(1.f, 1.f + val);
}
return AF_OK;
}
case AF_CONTROL_GET_PAN_BALANCE:
if (s->nch)
return AF_ERROR;
*(float*)arg = s->level[0][1] - s->level[1][0];
return AF_OK;
case AF_CONTROL_COMMAND: {
char **args = arg;
if (!strcmp(args[0], "set-matrix")) {
parse_matrix(af, args[1]);
return CONTROL_OK;
} else {
return CONTROL_ERROR;
}
}
}
return AF_UNKNOWN;
}
static int filter_frame(struct af_instance *af, struct mp_audio *c)
{
if (!c)
return 0;
struct mp_audio *l = mp_audio_pool_get(af->out_pool, &af->fmt_out, c->samples);
if (!l) {
talloc_free(c);
return -1;
}
mp_audio_copy_attributes(l, c);
af_pan_t* s = af->priv; // Setup for this instance
float *in = c->planes[0]; // Input audio data
float *out = NULL; // Output audio data
float *end = in+c->samples * c->nch; // End of loop
int nchi = c->nch; // Number of input channels
int ncho = l->nch; // Number of output channels
register int j, k;
out = l->planes[0];
// Execute panning
// FIXME: Too slow
while (in < end) {
for (j = 0; j < ncho; j++) {
register float x = 0.0;
register float *tin = in;
for (k = 0; k < nchi; k++)
x += tin[k] * s->level[j][k];
out[j] = x;
}
out += ncho;
in += nchi;
}
talloc_free(c);
af_add_output_frame(af, l);
return 0;
}
// Allocate memory and set function pointers
static int af_open(struct af_instance *af)
{
af->control = control;
af->filter_frame = filter_frame;
MP_WARN(af, "This filter is deprecated. Use lavfi pan instead.\n");
af_pan_t *s = af->priv;
int nch = s->nch;
if (nch && AF_OK != control(af, AF_CONTROL_SET_PAN_NOUT, &nch))
return AF_ERROR;
// Read pan values
if (s->matrixstr)
parse_matrix(af, s->matrixstr);
return AF_OK;
}
#define OPT_BASE_STRUCT af_pan_t
const struct af_info af_info_pan = {
.info = "Panning audio filter",
.name = "pan",
.open = af_open,
.priv_size = sizeof(af_pan_t),
.options = (const struct m_option[]) {
OPT_INTRANGE("channels", nch, 0, 0, AF_NCH),
OPT_STRING("matrix", matrixstr, 0),
{0}
},
};

View File

@ -1,188 +0,0 @@
/*
* Copyright (C)2002 Anders Johansson ajh@atri.curtin.edu.au
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include "common/common.h"
#include "af.h"
#include "demux/demux.h"
struct priv {
float level; // User-specified gain level for each channel
float rgain; // Replaygain level
int rgain_track; // Enable/disable track based replaygain
int rgain_album; // Enable/disable album based replaygain
float rgain_preamp; // Set replaygain pre-amplification
int rgain_clip; // Enable/disable clipping prevention
float replaygain_fallback;
int soft; // Enable/disable soft clipping
int fast; // Use fix-point volume control
int detach; // Detach if gain volume is neutral
float cfg_volume;
int warn;
};
// Convert to gain value from dB. input <= -200dB will become 0 gain.
static float from_dB(float in, float k, float mi, float ma)
{
if (in <= -200)
return 0.0;
return pow(10.0, MPCLAMP(in, mi, ma) / k);
}
static int control(struct af_instance *af, int cmd, void *arg)
{
struct priv *s = af->priv;
switch (cmd) {
case AF_CONTROL_REINIT: {
struct mp_audio *in = arg;
mp_audio_copy_config(af->data, in);
mp_audio_force_interleaved_format(af->data);
if (s->fast && af_fmt_from_planar(in->format) != AF_FORMAT_FLOAT) {
mp_audio_set_format(af->data, AF_FORMAT_S16);
} else {
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
}
if (af_fmt_is_planar(in->format))
mp_audio_set_format(af->data, af_fmt_to_planar(af->data->format));
s->rgain = 1.0;
struct replaygain_data *rg = af->replaygain_data;
if ((s->rgain_track || s->rgain_album) && rg) {
MP_VERBOSE(af, "Replaygain: Track=%f/%f Album=%f/%f\n",
rg->track_gain, rg->track_peak,
rg->album_gain, rg->album_peak);
float gain, peak;
if (s->rgain_track) {
gain = rg->track_gain;
peak = rg->track_peak;
} else {
gain = rg->album_gain;
peak = rg->album_peak;
}
gain += s->rgain_preamp;
s->rgain = from_dB(gain, 20.0, -200.0, 60.0);
MP_VERBOSE(af, "Applying replay-gain: %f\n", s->rgain);
if (!s->rgain_clip) { // clipping prevention
s->rgain = MPMIN(s->rgain, 1.0 / peak);
MP_VERBOSE(af, "...with clipping prevention: %f\n", s->rgain);
}
} else if (s->replaygain_fallback) {
s->rgain = from_dB(s->replaygain_fallback, 20.0, -200.0, 60.0);
MP_VERBOSE(af, "Applying fallback gain: %f\n", s->rgain);
}
if (s->detach && fabs(s->level * s->rgain - 1.0) < 0.00001)
return AF_DETACH;
return af_test_output(af, in);
}
case AF_CONTROL_SET_VOLUME:
s->level = *(float *)arg;
MP_VERBOSE(af, "volume gain: %f\n", s->level);
return AF_OK;
}
return AF_UNKNOWN;
}
static void filter_plane(struct af_instance *af, struct mp_audio *data, int p)
{
struct priv *s = af->priv;
float level = s->level * s->rgain * from_dB(s->cfg_volume, 20.0, -200.0, 60.0);
int num_samples = data->samples * data->spf;
if (af_fmt_from_planar(af->data->format) == AF_FORMAT_S16) {
int vol = 256.0 * level;
if (vol != 256) {
if (af_make_writeable(af, data) < 0)
return; // oom
int16_t *a = data->planes[p];
for (int i = 0; i < num_samples; i++) {
int x = (a[i] * vol) >> 8;
a[i] = MPCLAMP(x, SHRT_MIN, SHRT_MAX);
}
}
} else if (af_fmt_from_planar(af->data->format) == AF_FORMAT_FLOAT) {
float vol = level;
if (vol != 1.0) {
if (af_make_writeable(af, data) < 0)
return; // oom
float *a = data->planes[p];
for (int i = 0; i < num_samples; i++) {
float x = a[i] * vol;
a[i] = s->soft ? af_softclip(x) : MPCLAMP(x, -1.0, 1.0);
}
}
}
}
static int filter(struct af_instance *af, struct mp_audio *data)
{
if (data) {
for (int n = 0; n < data->num_planes; n++)
filter_plane(af, data, n);
af_add_output_frame(af, data);
}
return 0;
}
static int af_open(struct af_instance *af)
{
struct priv *s = af->priv;
if (s->warn)
MP_WARN(af, "This filter is deprecated. Use --volume directly.\n");
af->control = control;
af->filter_frame = filter;
s->level = 1.0;
return AF_OK;
}
#define OPT_BASE_STRUCT struct priv
// Description of this filter
const struct af_info af_info_volume = {
.info = "Volume control audio filter",
.name = "volume",
.open = af_open,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]) {
OPT_FLOATRANGE("volumedb", cfg_volume, 0, -200, 60),
OPT_FLAG("replaygain-track", rgain_track, 0),
OPT_FLAG("replaygain-album", rgain_album, 0),
OPT_FLOATRANGE("replaygain-preamp", rgain_preamp, 0, -15, 15),
OPT_FLAG("replaygain-clip", rgain_clip, 0),
OPT_FLOATRANGE("replaygain-fallback", replaygain_fallback, 0, -200, 60),
OPT_FLAG("softclip", soft, 0),
OPT_FLAG("s16", fast, 0),
OPT_FLAG("detach", detach, 0),
OPT_FLAG("warn", warn, 0, OPTDEF_INT(1)),
{0}
},
};

View File

@ -557,7 +557,6 @@ const m_option_t mp_opts[] = {
{"weak", -1})),
OPT_DOUBLE("audio-buffer", audio_buffer, M_OPT_MIN | M_OPT_MAX,
.min = 0, .max = 10),
OPT_FLOATRANGE("balance", balance, 0, -1, 1),
OPT_STRING("title", wintitle, 0),
OPT_STRING("force-media-title", media_title, 0),

View File

@ -107,7 +107,6 @@ typedef struct MPOpts {
float rgain_preamp; // Set replaygain pre-amplification
int rgain_clip; // Enable/disable clipping prevention
float rgain_fallback;
float balance;
int softvol_mute;
float softvol_max;
int gapless_audio;

View File

@ -185,57 +185,6 @@ void audio_update_volume(struct MPContext *mpctx)
gain *= compute_replaygain(mpctx);
if (opts->softvol_mute == 1)
gain = 0.0;
if (!af_control_any_rev(ao_c->af, AF_CONTROL_SET_VOLUME, &gain)) {
if (gain == 1.0)
return;
MP_VERBOSE(mpctx, "Inserting volume filter.\n");
char *args[] = {"warn", "no", NULL};
if (!(af_add(ao_c->af, "volume", "softvol", args)
&& af_control_any_rev(ao_c->af, AF_CONTROL_SET_VOLUME, &gain)))
MP_ERR(mpctx, "No volume control available.\n");
}
}
/* NOTE: Currently the balance code is seriously buggy: it always changes
* the af_pan mapping between the first two input channels and first two
* output channels to particular values. These values make sense for an
* af_pan instance that was automatically inserted for balance control
* only and is otherwise an identity transform, but if the filter was
* there for another reason, then ignoring and overriding the original
* values is completely wrong.
*/
void audio_update_balance(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
struct ao_chain *ao_c = mpctx->ao_chain;
if (!ao_c || ao_c->af->initialized < 1)
return;
float val = opts->balance;
if (af_control_any_rev(ao_c->af, AF_CONTROL_SET_PAN_BALANCE, &val))
return;
if (val == 0)
return;
struct af_instance *af_pan_balance;
if (!(af_pan_balance = af_add(ao_c->af, "pan", "autopan", NULL))) {
MP_ERR(mpctx, "No balance control available.\n");
return;
}
/* make all other channels pass through since by default pan blocks all */
for (int i = 2; i < AF_NCH; i++) {
float level[AF_NCH] = {0};
level[i] = 1.f;
af_control_ext_t arg_ext = { .ch = i, .arg = level };
af_pan_balance->control(af_pan_balance, AF_CONTROL_SET_PAN_LEVEL,
&arg_ext);
}
af_pan_balance->control(af_pan_balance, AF_CONTROL_SET_PAN_BALANCE, &val);
}
static int recreate_audio_filters(struct MPContext *mpctx)
@ -254,7 +203,6 @@ static int recreate_audio_filters(struct MPContext *mpctx)
MP_ERR(mpctx, "--softvol=no is not supported anymore.\n");
audio_update_volume(mpctx);
audio_update_balance(mpctx);
mp_notify(mpctx, MPV_EVENT_AUDIO_RECONFIG, NULL);
@ -289,7 +237,6 @@ int reinit_audio_filters(struct MPContext *mpctx)
#else /* HAVE_LIBAV */
void audio_update_volume(struct MPContext *mpctx) {}
void audio_update_balance(struct MPContext *mpctx) {}
int reinit_audio_filters(struct MPContext *mpctx) { return 0; }
#endif /* else HAVE_LIBAF */

View File

@ -2100,35 +2100,6 @@ static int mp_property_audio_out_params(void *ctx, struct m_property *prop,
return r;
}
/// Balance (RW)
static int mp_property_balance(void *ctx, struct m_property *prop,
int action, void *arg)
{
MPContext *mpctx = ctx;
if (action == M_PROPERTY_PRINT) {
char **str = arg;
float bal = mpctx->opts->balance;
if (bal == 0.f)
*str = talloc_strdup(NULL, "center");
else if (bal == -1.f)
*str = talloc_strdup(NULL, "left only");
else if (bal == 1.f)
*str = talloc_strdup(NULL, "right only");
else {
unsigned right = (bal + 1.f) / 2.f * 100.f;
*str = talloc_asprintf(NULL, "left %d%%, right %d%%",
100 - right, right);
}
return M_PROPERTY_OK;
}
int r = mp_property_generic_option(mpctx, prop, action, arg);
if (action == M_PROPERTY_SET)
audio_update_balance(mpctx);
return r;
}
static struct track* track_next(struct MPContext *mpctx, enum stream_type type,
int direction, struct track *track)
{
@ -4011,7 +3982,6 @@ static const struct m_property mp_properties_base[] = {
{"audio-params", mp_property_audio_params},
{"audio-out-params", mp_property_audio_out_params},
{"aid", mp_property_audio},
{"balance", mp_property_balance},
{"audio-device", mp_property_audio_device},
{"audio-device-list", mp_property_audio_devices},
{"current-ao", mp_property_ao},
@ -4167,7 +4137,7 @@ static const char *const *const mp_event_property_change[] = {
"colormatrix-primaries", "video-aspect", "video-dec-params",
"hwdec", "hwdec-current", "hwdec-interop"),
E(MPV_EVENT_AUDIO_RECONFIG, "audio-format", "audio-codec", "audio-bitrate",
"samplerate", "channels", "audio", "volume", "mute", "balance",
"samplerate", "channels", "audio", "volume", "mute",
"current-ao", "audio-codec-name", "audio-params",
"audio-out-params", "volume-max", "mixer-active"),
E(MPV_EVENT_SEEK, "seeking", "core-idle", "eof-reached"),
@ -4361,7 +4331,6 @@ static const struct property_osd_display {
{ "ao-mute", "AO Mute" },
{ "audio-delay", "A-V delay" },
{ "audio", "Audio" },
{ "balance", "Balance", .osd_progbar = OSD_BALANCE },
// video
{ "panscan", "Panscan", .osd_progbar = OSD_PANSCAN },
{ "taskbar-progress", "Progress in taskbar" },

View File

@ -184,16 +184,12 @@ def build(ctx):
( "audio/decode/ad_spdif.c" ),
( "audio/decode/dec_audio.c" ),
( "audio/filter/af.c", "libaf" ),
( "audio/filter/af_channels.c", "libaf" ),
( "audio/filter/af_equalizer.c", "libaf" ),
( "audio/filter/af_format.c", "libaf" ),
( "audio/filter/af_lavcac3enc.c", "libaf" ),
( "audio/filter/af_lavfi.c", "libaf" ),
( "audio/filter/af_lavrresample.c", "libaf" ),
( "audio/filter/af_pan.c", "libaf" ),
( "audio/filter/af_rubberband.c", "rubberband" ),
( "audio/filter/af_scaletempo.c", "libaf" ),
( "audio/filter/af_volume.c", "libaf" ),
( "audio/filter/tools.c", "libaf" ),
( "audio/out/ao.c" ),
( "audio/out/ao_alsa.c", "alsa" ),