summaryrefslogtreecommitdiffstats
path: root/libao2/pl_resample.c
diff options
context:
space:
mode:
authoranders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-12-20 15:30:22 +0000
committeranders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-12-20 15:30:22 +0000
commit30c2c12d50b1b6b3b2dda4ecc9ce40e951f57b33 (patch)
treefacfd96b7b63c5d3ef24cea4c7929d890a234b38 /libao2/pl_resample.c
parent12dd9ded9cb31217a9a43a5404e35c0b1559becf (diff)
downloadmpv-30c2c12d50b1b6b3b2dda4ecc9ce40e951f57b33.tar.bz2
mpv-30c2c12d50b1b6b3b2dda4ecc9ce40e951f57b33.tar.xz
Added plugin for fractional resampling (alpha code)
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@3632 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libao2/pl_resample.c')
-rw-r--r--libao2/pl_resample.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/libao2/pl_resample.c b/libao2/pl_resample.c
new file mode 100644
index 0000000000..3ab049ca08
--- /dev/null
+++ b/libao2/pl_resample.c
@@ -0,0 +1,239 @@
+/*=============================================================================
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
+//
+//=============================================================================
+*/
+
+/* This audio output plugin changes the sample rate. The output
+ samplerate from this plugin is specified by using the switch
+ `fout=F' where F is the desired output sample frequency
+*/
+
+#define PLUGIN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "audio_out.h"
+#include "audio_plugin.h"
+#include "audio_plugin_internal.h"
+#include "afmt.h"
+//#include "../config.h"
+
+static ao_info_t info =
+{
+ "Sample frequency conversion audio plugin",
+ "resample",
+ "Anders",
+ ""
+};
+
+LIBAO_PLUGIN_EXTERN(resample)
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+/* Below definition selects the length of each poly phase component.
+ Valid definitions are L4 and L8, where the number denotes the
+ length of the filter. This definition affects the computational
+ complexity (see play()), the performance (see filter.h) and the
+ memory usage. For now the filterlenght is choosen to 4 and without
+ assembly optimization if no SSE is present.
+*/
+#ifdef HAVE_SSE
+#define L8 1 // Filter bank type
+#define W W8 // Filter bank parameters
+#define L 8 // Filter length
+#else
+#define L4 1
+#define W W4
+#define L 4
+#endif
+
+#define CH 6 // Max number of channels
+#define UP 128 /* Up sampling factor. Increasing this value will
+ improve frequency accuracy. Think about the L1
+ cashing of filter parameters - how big can it be? */
+
+#include "fir.h"
+#include "filter.h"
+
+// local data
+typedef struct pl_resample_s
+{
+ int16_t* data; // Data buffer
+ int16_t* w; // Current filter weights
+ uint16_t dn; // Down sampling factor
+ uint16_t up; // Up sampling factor
+ int channels; // Number of channels
+ int len; // Lenght of buffer
+ int bypass; // Bypass this plugin
+ int16_t ws[UP*L]; // List of all available filters
+ int16_t xs[CH][L*2]; // Circular buffers
+} pl_resample_t;
+
+static pl_resample_t pl_resample = {NULL,NULL,1,1,1,0,0,W};
+
+// to set/get/query special features/parameters
+static int control(int cmd,int arg){
+ switch(cmd){
+ case AOCONTROL_PLUGIN_SET_LEN:
+ if(pl_resample.data)
+ free(pl_resample.data);
+ pl_resample.len = ao_plugin_data.len;
+ pl_resample.data=(int16_t*)malloc(pl_resample.len);
+ if(!pl_resample.data)
+ return CONTROL_ERROR;
+ ao_plugin_data.len = (int)((double)ao_plugin_data.len *
+ ((double)pl_resample.up)/
+ ((double)pl_resample.dn));
+ return CONTROL_OK;
+ }
+ return -1;
+}
+
+// open & setup audio device
+// return: 1=success 0=fail
+static int init(){
+ int fin=ao_plugin_data.rate;
+ int fout=ao_plugin_cfg.pl_resample_fout;
+ pl_resample.w=pl_resample.ws;
+ pl_resample.up=UP;
+
+ // Sheck input format
+ if(ao_plugin_data.format != AFMT_S16_LE){
+ fprintf(stderr,"[pl_resample] Input audio format not yet suported. \n");
+ return 0;
+ }
+ // Sanity check and calculate down sampling factor
+ if((float)max(fin,fout)/(float)min(fin,fout) > 10){
+ fprintf(stderr,"[pl_resample] The difference between fin and fout is too large.\n");
+ return 0;
+ }
+ pl_resample.dn=(int)(0.5+((float)(fin*pl_resample.up))/((float)fout));
+ if(pl_resample.dn == pl_resample.up){
+ fprintf(stderr,"[pl_resample] Fin is too close to fout no conversion is needed.\n");
+ pl_resample.bypass=1;
+ return 1;
+ }
+ pl_resample.channels=ao_plugin_data.channels;
+ if(ao_plugin_data.channels>CH){
+ fprintf(stderr,"[pl_resample] Too many channels, max is 6.\n");
+ return 0;
+ }
+
+ // Tell the world what we are up to
+ printf("[pl_resample] Up=%i, Down=%i, True fout=%f\n",
+ pl_resample.up,pl_resample.dn,
+ ((float)fin*pl_resample.up)/((float)pl_resample.dn));
+
+ // This plugin changes buffersize and adds some delay
+ ao_plugin_data.sz_mult/=((float)pl_resample.up)/((float)pl_resample.dn);
+ ao_plugin_data.delay_fix-= ((float)L/2) * (1/fout);
+ ao_plugin_data.rate=fout;
+ return 1;
+}
+
+// close plugin
+static void uninit(){
+ if(pl_resample.data)
+ free(pl_resample.data);
+ pl_resample.data=NULL;
+}
+
+// empty buffers
+static void reset(){
+}
+
+// processes 'ao_plugin_data.len' bytes of 'data'
+// called for every block of data
+// FIXME: this routine needs to be optimized (it is probably possible to do a lot here)
+static int play(){
+ static uint16_t pwi = 0; // Index for w
+ static uint16_t pxi = 0; // Index for circular queue
+ static uint16_t pi = 1; // Number of new samples to put in x queue
+
+ uint16_t ci = pl_resample.channels; // Index for channels
+ uint16_t len = 0; // Number of output samples
+ uint16_t nch = pl_resample.channels; // Number of channels
+ uint16_t inc = pl_resample.dn/pl_resample.up;
+ uint16_t level = pl_resample.dn%pl_resample.up;
+ uint16_t up = pl_resample.up;
+ uint16_t dn = pl_resample.dn;
+
+ register uint16_t i,wi,xi; // Temporary indexes
+
+ if(pl_resample.bypass)
+ return 1;
+
+ // Index current channel
+ while(ci--){
+ // Temporary pointers
+ register int16_t* x = pl_resample.xs[ci];
+ register int16_t* in = ((int16_t*)ao_plugin_data.data)+ci;
+ register int16_t* out = pl_resample.data+ci;
+ // Block loop end
+ register int16_t* end = in+ao_plugin_data.len/2;
+ i = pi; wi = pwi; xi = pxi;
+
+ LOAD_QUE(x);
+ if(0!=i) goto L1;
+ while(in < end){
+ // Update wi to point at the correct polyphase component
+ wi=(wi+dn)%up;
+
+ /* Update circular buffer x. This loop will be updated 0 or 1 time
+ for upsamling and inc or inc + 1 times for downsampling */
+ if(wi<level) goto L3;
+ if(0==i) goto L2;
+ L1: i--;
+ L3: UPDATE_QUE(in);
+ in+=nch;
+ if(in >= end) goto L2;
+ if(i) goto L1;
+ L2: if(i) goto L5;
+ i=inc;
+
+ /* Get the correct polyphase component and the correct startpoint
+ in the circular bufer and run the FIR filter */
+ FIR((&x[xi]),(&pl_resample.w[wi*L]),out);
+ len++;
+ out+=nch;
+ }
+L5:
+ SAVE_QUE(x);
+ }
+
+ // Save values that needs to be kept for next time
+ pwi = wi;
+ pxi = xi;
+ pi = i;
+ // Set new data
+ ao_plugin_data.len=len*2;
+ ao_plugin_data.data=pl_resample.data;
+ return 1;
+}
+
+
+
+
+