comparison libao2/pl_resample.c @ 3631:5f5189ac6a41

Added plugin for fractional resampling (alpha code)
author anders
date Thu, 20 Dec 2001 15:30:22 +0000
parents
children d6f8feeac656
comparison
equal deleted inserted replaced
3630:f24527fc1b79 3631:5f5189ac6a41
1 /*=============================================================================
2 //
3 // This file is part of mplayer.
4 //
5 // mplayer is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // mplayer is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with mplayer; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 //
19 // Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
20 //
21 //=============================================================================
22 */
23
24 /* This audio output plugin changes the sample rate. The output
25 samplerate from this plugin is specified by using the switch
26 `fout=F' where F is the desired output sample frequency
27 */
28
29 #define PLUGIN
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <inttypes.h>
35
36 #include "audio_out.h"
37 #include "audio_plugin.h"
38 #include "audio_plugin_internal.h"
39 #include "afmt.h"
40 //#include "../config.h"
41
42 static ao_info_t info =
43 {
44 "Sample frequency conversion audio plugin",
45 "resample",
46 "Anders",
47 ""
48 };
49
50 LIBAO_PLUGIN_EXTERN(resample)
51
52 #define min(a,b) (((a) < (b)) ? (a) : (b))
53 #define max(a,b) (((a) > (b)) ? (a) : (b))
54
55 /* Below definition selects the length of each poly phase component.
56 Valid definitions are L4 and L8, where the number denotes the
57 length of the filter. This definition affects the computational
58 complexity (see play()), the performance (see filter.h) and the
59 memory usage. For now the filterlenght is choosen to 4 and without
60 assembly optimization if no SSE is present.
61 */
62 #ifdef HAVE_SSE
63 #define L8 1 // Filter bank type
64 #define W W8 // Filter bank parameters
65 #define L 8 // Filter length
66 #else
67 #define L4 1
68 #define W W4
69 #define L 4
70 #endif
71
72 #define CH 6 // Max number of channels
73 #define UP 128 /* Up sampling factor. Increasing this value will
74 improve frequency accuracy. Think about the L1
75 cashing of filter parameters - how big can it be? */
76
77 #include "fir.h"
78 #include "filter.h"
79
80 // local data
81 typedef struct pl_resample_s
82 {
83 int16_t* data; // Data buffer
84 int16_t* w; // Current filter weights
85 uint16_t dn; // Down sampling factor
86 uint16_t up; // Up sampling factor
87 int channels; // Number of channels
88 int len; // Lenght of buffer
89 int bypass; // Bypass this plugin
90 int16_t ws[UP*L]; // List of all available filters
91 int16_t xs[CH][L*2]; // Circular buffers
92 } pl_resample_t;
93
94 static pl_resample_t pl_resample = {NULL,NULL,1,1,1,0,0,W};
95
96 // to set/get/query special features/parameters
97 static int control(int cmd,int arg){
98 switch(cmd){
99 case AOCONTROL_PLUGIN_SET_LEN:
100 if(pl_resample.data)
101 free(pl_resample.data);
102 pl_resample.len = ao_plugin_data.len;
103 pl_resample.data=(int16_t*)malloc(pl_resample.len);
104 if(!pl_resample.data)
105 return CONTROL_ERROR;
106 ao_plugin_data.len = (int)((double)ao_plugin_data.len *
107 ((double)pl_resample.up)/
108 ((double)pl_resample.dn));
109 return CONTROL_OK;
110 }
111 return -1;
112 }
113
114 // open & setup audio device
115 // return: 1=success 0=fail
116 static int init(){
117 int fin=ao_plugin_data.rate;
118 int fout=ao_plugin_cfg.pl_resample_fout;
119 pl_resample.w=pl_resample.ws;
120 pl_resample.up=UP;
121
122 // Sheck input format
123 if(ao_plugin_data.format != AFMT_S16_LE){
124 fprintf(stderr,"[pl_resample] Input audio format not yet suported. \n");
125 return 0;
126 }
127 // Sanity check and calculate down sampling factor
128 if((float)max(fin,fout)/(float)min(fin,fout) > 10){
129 fprintf(stderr,"[pl_resample] The difference between fin and fout is too large.\n");
130 return 0;
131 }
132 pl_resample.dn=(int)(0.5+((float)(fin*pl_resample.up))/((float)fout));
133 if(pl_resample.dn == pl_resample.up){
134 fprintf(stderr,"[pl_resample] Fin is too close to fout no conversion is needed.\n");
135 pl_resample.bypass=1;
136 return 1;
137 }
138 pl_resample.channels=ao_plugin_data.channels;
139 if(ao_plugin_data.channels>CH){
140 fprintf(stderr,"[pl_resample] Too many channels, max is 6.\n");
141 return 0;
142 }
143
144 // Tell the world what we are up to
145 printf("[pl_resample] Up=%i, Down=%i, True fout=%f\n",
146 pl_resample.up,pl_resample.dn,
147 ((float)fin*pl_resample.up)/((float)pl_resample.dn));
148
149 // This plugin changes buffersize and adds some delay
150 ao_plugin_data.sz_mult/=((float)pl_resample.up)/((float)pl_resample.dn);
151 ao_plugin_data.delay_fix-= ((float)L/2) * (1/fout);
152 ao_plugin_data.rate=fout;
153 return 1;
154 }
155
156 // close plugin
157 static void uninit(){
158 if(pl_resample.data)
159 free(pl_resample.data);
160 pl_resample.data=NULL;
161 }
162
163 // empty buffers
164 static void reset(){
165 }
166
167 // processes 'ao_plugin_data.len' bytes of 'data'
168 // called for every block of data
169 // FIXME: this routine needs to be optimized (it is probably possible to do a lot here)
170 static int play(){
171 static uint16_t pwi = 0; // Index for w
172 static uint16_t pxi = 0; // Index for circular queue
173 static uint16_t pi = 1; // Number of new samples to put in x queue
174
175 uint16_t ci = pl_resample.channels; // Index for channels
176 uint16_t len = 0; // Number of output samples
177 uint16_t nch = pl_resample.channels; // Number of channels
178 uint16_t inc = pl_resample.dn/pl_resample.up;
179 uint16_t level = pl_resample.dn%pl_resample.up;
180 uint16_t up = pl_resample.up;
181 uint16_t dn = pl_resample.dn;
182
183 register uint16_t i,wi,xi; // Temporary indexes
184
185 if(pl_resample.bypass)
186 return 1;
187
188 // Index current channel
189 while(ci--){
190 // Temporary pointers
191 register int16_t* x = pl_resample.xs[ci];
192 register int16_t* in = ((int16_t*)ao_plugin_data.data)+ci;
193 register int16_t* out = pl_resample.data+ci;
194 // Block loop end
195 register int16_t* end = in+ao_plugin_data.len/2;
196 i = pi; wi = pwi; xi = pxi;
197
198 LOAD_QUE(x);
199 if(0!=i) goto L1;
200 while(in < end){
201 // Update wi to point at the correct polyphase component
202 wi=(wi+dn)%up;
203
204 /* Update circular buffer x. This loop will be updated 0 or 1 time
205 for upsamling and inc or inc + 1 times for downsampling */
206 if(wi<level) goto L3;
207 if(0==i) goto L2;
208 L1: i--;
209 L3: UPDATE_QUE(in);
210 in+=nch;
211 if(in >= end) goto L2;
212 if(i) goto L1;
213 L2: if(i) goto L5;
214 i=inc;
215
216 /* Get the correct polyphase component and the correct startpoint
217 in the circular bufer and run the FIR filter */
218 FIR((&x[xi]),(&pl_resample.w[wi*L]),out);
219 len++;
220 out+=nch;
221 }
222 L5:
223 SAVE_QUE(x);
224 }
225
226 // Save values that needs to be kept for next time
227 pwi = wi;
228 pxi = xi;
229 pi = i;
230 // Set new data
231 ao_plugin_data.len=len*2;
232 ao_plugin_data.data=pl_resample.data;
233 return 1;
234 }
235
236
237
238
239