diff options
author | wm4 <wm4@nowhere> | 2012-11-05 17:02:04 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2012-11-12 20:06:14 +0100 |
commit | d4bdd0473d6f43132257c9fb3848d829755167a3 (patch) | |
tree | 8021c2f7da1841393c8c832105e20cd527826d6c /audio/filter/af_surround.c | |
parent | bd48deba77bd5582c5829d6fe73a7d2571088aba (diff) | |
download | mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.bz2 mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.xz |
Rename directories, move files (step 1 of 2) (does not compile)
Tis drops the silly lib prefixes, and attempts to organize the tree in
a more logical way. Make the top-level directory less cluttered as
well.
Renames the following directories:
libaf -> audio/filter
libao2 -> audio/out
libvo -> video/out
libmpdemux -> demux
Split libmpcodecs:
vf* -> video/filter
vd*, dec_video.* -> video/decode
mp_image*, img_format*, ... -> video/
ad*, dec_audio.* -> audio/decode
libaf/format.* is moved to audio/ - this is similar to how mp_image.*
is located in video/.
Move most top-level .c/.h files to core. (talloc.c/.h is left on top-
level, because it's external.) Park some of the more annoying files
in compat/. Some of these are relicts from the time mplayer used
ffmpeg internals.
sub/ is not split, because it's too much of a mess (subtitle code is
mixed with OSD display and rendering).
Maybe the organization of core is not ideal: it mixes playback core
(like mplayer.c) and utility helpers (like bstr.c/h). Should the need
arise, the playback core will be moved somewhere else, while core
contains all helper and common code.
Diffstat (limited to 'audio/filter/af_surround.c')
-rw-r--r-- | audio/filter/af_surround.c | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/audio/filter/af_surround.c b/audio/filter/af_surround.c new file mode 100644 index 0000000000..57288d6ba2 --- /dev/null +++ b/audio/filter/af_surround.c @@ -0,0 +1,273 @@ +/* + * Filter to do simple decoding of matrixed surround sound. + * This will provide a (basic) surround-sound effect from + * audio encoded for Dolby Surround, Pro Logic etc. + * + * original author: Steve Davies <steve@daviesfam.org> + * + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* The principle: Make rear channels by extracting anti-phase data + from the front channels, delay by 20ms and feed to rear in anti-phase +*/ + + +/* SPLITREAR: Define to decode two distinct rear channels - this + doesn't work so well in practice because separation in a passive + matrix is not high. C (dialogue) to Ls and Rs 14dB or so - so + dialogue leaks to the rear. Still - give it a try and send + feedback. Comment this define for old behavior of a single + surround sent to rear in anti-phase */ +#define SPLITREAR 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "af.h" +#include "dsp.h" + +#define L 32 // Length of fir filter +#define LD 65536 // Length of delay buffer + +// 32 Tap fir filter loop unrolled +#define FIR(x,w,y) \ + y = ( w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] \ + + w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] \ + + w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11] \ + + w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15] \ + + w[16]*x[16]+w[17]*x[17]+w[18]*x[18]+w[19]*x[19] \ + + w[20]*x[20]+w[21]*x[21]+w[22]*x[22]+w[23]*x[23] \ + + w[24]*x[24]+w[25]*x[25]+w[26]*x[26]+w[27]*x[27] \ + + w[28]*x[28]+w[29]*x[29]+w[30]*x[30]+w[31]*x[31]) + +// Add to circular queue macro + update index +#ifdef SPLITREAR +#define ADDQUE(qi,rq,lq,r,l)\ + lq[qi]=lq[qi+L]=(l);\ + rq[qi]=rq[qi+L]=(r);\ + qi=(qi-1)&(L-1); +#else +#define ADDQUE(qi,lq,l)\ + lq[qi]=lq[qi+L]=(l);\ + qi=(qi-1)&(L-1); +#endif + +// Macro for updating queue index in delay queues +#define UPDATEQI(qi) qi=(qi+1)&(LD-1) + +// instance data +typedef struct af_surround_s +{ + float lq[2*L]; // Circular queue for filtering left rear channel + float rq[2*L]; // Circular queue for filtering right rear channel + float w[L]; // FIR filter coefficients for surround sound 7kHz low-pass + float* dr; // Delay queue right rear channel + float* dl; // Delay queue left rear channel + float d; // Delay time + int i; // Position in circular buffer + int wi; // Write index for delay queue + int ri; // Read index for delay queue +}af_surround_t; + +// Initialization and runtime control +static int control(struct af_instance* af, int cmd, void* arg) +{ + af_surround_t *s = af->setup; + switch(cmd){ + case AF_CONTROL_REINIT:{ + float fc; + af->data->rate = ((struct mp_audio*)arg)->rate; + af->data->nch = ((struct mp_audio*)arg)->nch*2; + af->data->format = AF_FORMAT_FLOAT_NE; + af->data->bps = 4; + + if (af->data->nch != 4){ + mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Only stereo input is supported.\n"); + return AF_DETACH; + } + // Surround filer coefficients + fc = 2.0 * 7000.0/(float)af->data->rate; + if (-1 == af_filter_design_fir(L, s->w, &fc, LP|HAMMING, 0)){ + mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Unable to design low-pass filter.\n"); + return AF_ERROR; + } + + // Free previous delay queues + free(s->dl); + free(s->dr); + // Allocate new delay queues + s->dl = calloc(LD,af->data->bps); + s->dr = calloc(LD,af->data->bps); + if((NULL == s->dl) || (NULL == s->dr)) + mp_msg(MSGT_AFILTER, MSGL_FATAL, "[delay] Out of memory\n"); + + // Initialize delay queue index + if(AF_OK != af_from_ms(1, &s->d, &s->wi, af->data->rate, 0.0, 1000.0)) + return AF_ERROR; +// printf("%i\n",s->wi); + s->ri = 0; + + if((af->data->format != ((struct mp_audio*)arg)->format) || + (af->data->bps != ((struct mp_audio*)arg)->bps)){ + ((struct mp_audio*)arg)->format = af->data->format; + ((struct mp_audio*)arg)->bps = af->data->bps; + return AF_FALSE; + } + return AF_OK; + } + case AF_CONTROL_COMMAND_LINE:{ + float d = 0; + sscanf((char*)arg,"%f",&d); + if ((d < 0) || (d > 1000)){ + mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Invalid delay time, valid time values" + " are 0ms to 1000ms current value is %0.3f ms\n",d); + return AF_ERROR; + } + s->d = d; + return AF_OK; + } + } + return AF_UNKNOWN; +} + +// Deallocate memory +static void uninit(struct af_instance* af) +{ + if(af->data) + free(af->data->audio); + free(af->data); + free(af->setup); +} + +// The beginnings of an active matrix... +static float steering_matrix[][12] = { +// LL RL LR RR LS RS +// LLs RLs LRs RRs LC RC + {.707, .0, .0, .707, .5, -.5, + .5878, -.3928, .3928, -.5878, .5, .5}, +}; + +// Experimental moving average dominance +//static int amp_L = 0, amp_R = 0, amp_C = 0, amp_S = 0; + +// Filter data through filter +static struct mp_audio* play(struct af_instance* af, struct mp_audio* data){ + af_surround_t* s = (af_surround_t*)af->setup; + float* m = steering_matrix[0]; + float* in = data->audio; // Input audio data + float* out = NULL; // Output audio data + float* end = in + data->len / sizeof(float); // Loop end + int i = s->i; // Filter queue index + int ri = s->ri; // Read index for delay queue + int wi = s->wi; // Write index for delay queue + + if (AF_OK != RESIZE_LOCAL_BUFFER(af, data)) + return NULL; + + out = af->data->audio; + + while(in < end){ + /* Dominance: + abs(in[0]) abs(in[1]); + abs(in[0]+in[1]) abs(in[0]-in[1]); + 10 * log( abs(in[0]) / (abs(in[1])|1) ); + 10 * log( abs(in[0]+in[1]) / (abs(in[0]-in[1])|1) ); */ + + /* About volume balancing... + Surround encoding does the following: + Lt=L+.707*C+.707*S, Rt=R+.707*C-.707*S + So S should be extracted as: + (Lt-Rt) + But we are splitting the S to two output channels, so we + must take 3dB off as we split it: + Ls=Rs=.707*(Lt-Rt) + Trouble is, Lt could be +1, Rt -1, so possibility that S will + overflow. So to avoid that, we cut L/R by 3dB (*.707), and S by + 6dB (/2). This keeps the overall balance, but guarantees no + overflow. */ + + // Output front left and right + out[0] = m[0]*in[0] + m[1]*in[1]; + out[1] = m[2]*in[0] + m[3]*in[1]; + + // Low-pass output @ 7kHz + FIR((&s->lq[i]), s->w, s->dl[wi]); + + // Delay output by d ms + out[2] = s->dl[ri]; + +#ifdef SPLITREAR + // Low-pass output @ 7kHz + FIR((&s->rq[i]), s->w, s->dr[wi]); + + // Delay output by d ms + out[3] = s->dr[ri]; +#else + out[3] = -out[2]; +#endif + + // Update delay queues indexes + UPDATEQI(ri); + UPDATEQI(wi); + + // Calculate and save surround in circular queue +#ifdef SPLITREAR + ADDQUE(i, s->rq, s->lq, m[6]*in[0]+m[7]*in[1], m[8]*in[0]+m[9]*in[1]); +#else + ADDQUE(i, s->lq, m[4]*in[0]+m[5]*in[1]); +#endif + + // Next sample... + in = &in[data->nch]; + out = &out[af->data->nch]; + } + + // Save indexes + s->i = i; s->ri = ri; s->wi = wi; + + // Set output data + data->audio = af->data->audio; + data->len *= 2; + data->nch = af->data->nch; + + return data; +} + +static int af_open(struct af_instance* af){ + af->control=control; + af->uninit=uninit; + af->play=play; + af->mul=2; + af->data=calloc(1,sizeof(struct mp_audio)); + af->setup=calloc(1,sizeof(af_surround_t)); + if(af->data == NULL || af->setup == NULL) + return AF_ERROR; + ((af_surround_t*)af->setup)->d = 20; + return AF_OK; +} + +struct af_info af_info_surround = +{ + "Surround decoder filter", + "surround", + "Steve Davies <steve@daviesfam.org>", + "", + AF_FLAGS_NOT_REENTRANT, + af_open +}; |