Mercurial > mplayer.hg
annotate libao2/pl_resample.c @ 5264:d3846ebe974d
added zlib
author | alex |
---|---|
date | Fri, 22 Mar 2002 22:14:01 +0000 |
parents | c2bb05709676 |
children | c4434bdf6e51 |
rev | line source |
---|---|
3631 | 1 /*============================================================================= |
2 // | |
4049 | 3 // This software has been released under the terms of the GNU Public |
4 // license. See http://www.gnu.org/copyleft/gpl.html for details. | |
3631 | 5 // |
6 // Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au | |
7 // | |
8 //============================================================================= | |
9 */ | |
10 | |
11 /* This audio output plugin changes the sample rate. The output | |
12 samplerate from this plugin is specified by using the switch | |
13 `fout=F' where F is the desired output sample frequency | |
14 */ | |
15 | |
16 #define PLUGIN | |
17 | |
18 #include <stdio.h> | |
19 #include <stdlib.h> | |
20 #include <unistd.h> | |
21 #include <inttypes.h> | |
22 | |
23 #include "audio_out.h" | |
24 #include "audio_plugin.h" | |
25 #include "audio_plugin_internal.h" | |
26 #include "afmt.h" | |
4535 | 27 #include "../config.h" |
3631 | 28 |
29 static ao_info_t info = | |
30 { | |
31 "Sample frequency conversion audio plugin", | |
32 "resample", | |
33 "Anders", | |
34 "" | |
35 }; | |
36 | |
37 LIBAO_PLUGIN_EXTERN(resample) | |
38 | |
39 #define min(a,b) (((a) < (b)) ? (a) : (b)) | |
40 #define max(a,b) (((a) > (b)) ? (a) : (b)) | |
41 | |
42 /* Below definition selects the length of each poly phase component. | |
4725
534ef9323eca
MMX part rewritten and 16 tap filter added for better sound qualty
anders
parents:
4535
diff
changeset
|
43 Valid definitions are L8 and L16, where the number denotes the |
3631 | 44 length of the filter. This definition affects the computational |
45 complexity (see play()), the performance (see filter.h) and the | |
4725
534ef9323eca
MMX part rewritten and 16 tap filter added for better sound qualty
anders
parents:
4535
diff
changeset
|
46 memory usage. The filterlenght is choosen to 8 if the machine is |
534ef9323eca
MMX part rewritten and 16 tap filter added for better sound qualty
anders
parents:
4535
diff
changeset
|
47 slow and to 16 if the machine is fast and has MMX. |
3631 | 48 */ |
4171
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
49 |
4725
534ef9323eca
MMX part rewritten and 16 tap filter added for better sound qualty
anders
parents:
4535
diff
changeset
|
50 #if !defined(HAVE_SSE) && !defined(HAVE_3DNOW) //This machine is slow |
4789 | 51 |
3631 | 52 #define W W8 // Filter bank parameters |
53 #define L 8 // Filter length | |
4789 | 54 #ifdef HAVE_MMX |
55 #define FIR(x,w,y) *y=(int16_t)firn(x,w,8); | |
56 #else /* HAVE_MMX */ | |
57 // Unrolled loop to speed up execution | |
58 #define FIR(x,w,y){ \ | |
59 int16_t a = (w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3]) >> 16; \ | |
60 int16_t b = (w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7]) >> 16; \ | |
61 y[0] = a+b; \ | |
62 } | |
63 #endif /* HAVE_MMX */ | |
64 | |
65 #else /* Fast machine */ | |
66 | |
4725
534ef9323eca
MMX part rewritten and 16 tap filter added for better sound qualty
anders
parents:
4535
diff
changeset
|
67 #define W W16 |
534ef9323eca
MMX part rewritten and 16 tap filter added for better sound qualty
anders
parents:
4535
diff
changeset
|
68 #define L 16 |
4789 | 69 #define FIR(x,w,y) *y=(int16_t)firn(x,w,16); |
70 | |
4725
534ef9323eca
MMX part rewritten and 16 tap filter added for better sound qualty
anders
parents:
4535
diff
changeset
|
71 #endif |
3631 | 72 |
73 #define CH 6 // Max number of channels | |
74 #define UP 128 /* Up sampling factor. Increasing this value will | |
75 improve frequency accuracy. Think about the L1 | |
76 cashing of filter parameters - how big can it be? */ | |
77 | |
78 #include "fir.h" | |
79 #include "filter.h" | |
80 | |
81 // local data | |
82 typedef struct pl_resample_s | |
83 { | |
84 int16_t* data; // Data buffer | |
85 int16_t* w; // Current filter weights | |
86 uint16_t dn; // Down sampling factor | |
87 uint16_t up; // Up sampling factor | |
88 int channels; // Number of channels | |
89 int len; // Lenght of buffer | |
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 | |
4171
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
94 static pl_resample_t pl_resample = {NULL,NULL,1,1,1,0,W}; |
3631 | 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 * | |
4374
0a95c5074c50
Fixed sig 11 caused by resampling plugin, some cosmetic changes and speed improvements
anders
parents:
4171
diff
changeset
|
107 ((double)pl_resample.dn)/ |
0a95c5074c50
Fixed sig 11 caused by resampling plugin, some cosmetic changes and speed improvements
anders
parents:
4171
diff
changeset
|
108 ((double)pl_resample.up)); |
3631 | 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)); | |
4171
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
133 |
3631 | 134 pl_resample.channels=ao_plugin_data.channels; |
135 if(ao_plugin_data.channels>CH){ | |
136 fprintf(stderr,"[pl_resample] Too many channels, max is 6.\n"); | |
137 return 0; | |
138 } | |
139 | |
140 // Tell the world what we are up to | |
141 printf("[pl_resample] Up=%i, Down=%i, True fout=%f\n", | |
142 pl_resample.up,pl_resample.dn, | |
143 ((float)fin*pl_resample.up)/((float)pl_resample.dn)); | |
144 | |
145 // This plugin changes buffersize and adds some delay | |
146 ao_plugin_data.sz_mult/=((float)pl_resample.up)/((float)pl_resample.dn); | |
147 ao_plugin_data.delay_fix-= ((float)L/2) * (1/fout); | |
148 ao_plugin_data.rate=fout; | |
149 return 1; | |
150 } | |
151 | |
152 // close plugin | |
153 static void uninit(){ | |
154 if(pl_resample.data) | |
155 free(pl_resample.data); | |
156 pl_resample.data=NULL; | |
157 } | |
158 | |
159 // empty buffers | |
160 static void reset(){ | |
161 } | |
162 | |
163 // processes 'ao_plugin_data.len' bytes of 'data' | |
164 // called for every block of data | |
165 // FIXME: this routine needs to be optimized (it is probably possible to do a lot here) | |
166 static int play(){ | |
4171
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
167 if(pl_resample.up==pl_resample.dn){ |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
168 register int16_t* in = ((int16_t*)ao_plugin_data.data); |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
169 register int16_t* end = in+ao_plugin_data.len/2; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
170 while(in < end) *in=(*in++)>>1; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
171 return 1; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
172 } |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
173 if(pl_resample.up>pl_resample.dn) |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
174 return upsample(); |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
175 if(pl_resample.up<pl_resample.dn) |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
176 return downsample(); |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
177 } |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
178 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
179 int upsample(){ |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
180 static uint16_t pwi = 0; // Index for w |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
181 static uint16_t pxi = 0; // Index for circular queue |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
182 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
183 uint16_t ci = pl_resample.channels; // Index for channels |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
184 uint16_t nch = pl_resample.channels; // Number of channels |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
185 uint16_t len = 0; // Number of input samples |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
186 uint16_t inc = pl_resample.up/pl_resample.dn; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
187 uint16_t level = pl_resample.up%pl_resample.dn; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
188 uint16_t up = pl_resample.up; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
189 uint16_t dn = pl_resample.dn; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
190 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
191 register int16_t* w = pl_resample.w; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
192 register uint16_t wi,xi; // Temporary indexes |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
193 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
194 // Index current channel |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
195 while(ci--){ |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
196 // Temporary pointers |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
197 register int16_t* x = pl_resample.xs[ci]; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
198 register int16_t* in = ((int16_t*)ao_plugin_data.data)+ci; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
199 register int16_t* out = pl_resample.data+ci; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
200 int16_t* end = in+ao_plugin_data.len/2; // Block loop end |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
201 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
202 wi = pwi; xi = pxi; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
203 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
204 while(in < end){ |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
205 register uint16_t i = inc; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
206 if(wi<level) i++; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
207 |
4789 | 208 xi=updateq(x,in,xi,L); |
4171
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
209 in+=nch; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
210 while(i--){ |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
211 // Run the FIR filter |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
212 FIR((&x[xi]),(&w[wi*L]),out); |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
213 len++; out+=nch; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
214 // Update wi to point at the correct polyphase component |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
215 wi=(wi+dn)%up; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
216 } |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
217 } |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
218 } |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
219 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
220 // Save values that needs to be kept for next time |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
221 pwi = wi; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
222 pxi = xi; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
223 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
224 // Set new data |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
225 ao_plugin_data.len=len*2; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
226 ao_plugin_data.data=pl_resample.data; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
227 return 1; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
228 } |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
229 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
230 int downsample(){ |
3631 | 231 static uint16_t pwi = 0; // Index for w |
232 static uint16_t pxi = 0; // Index for circular queue | |
233 static uint16_t pi = 1; // Number of new samples to put in x queue | |
234 | |
235 uint16_t ci = pl_resample.channels; // Index for channels | |
4171
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
236 uint16_t len = 0; // Number of input samples |
3631 | 237 uint16_t nch = pl_resample.channels; // Number of channels |
238 uint16_t inc = pl_resample.dn/pl_resample.up; | |
239 uint16_t level = pl_resample.dn%pl_resample.up; | |
240 uint16_t up = pl_resample.up; | |
241 uint16_t dn = pl_resample.dn; | |
242 | |
243 register uint16_t i,wi,xi; // Temporary indexes | |
244 | |
245 | |
246 // Index current channel | |
247 while(ci--){ | |
248 // Temporary pointers | |
249 register int16_t* x = pl_resample.xs[ci]; | |
250 register int16_t* in = ((int16_t*)ao_plugin_data.data)+ci; | |
251 register int16_t* out = pl_resample.data+ci; | |
252 // Block loop end | |
253 register int16_t* end = in+ao_plugin_data.len/2; | |
254 i = pi; wi = pwi; xi = pxi; | |
255 | |
256 while(in < end){ | |
257 | |
4789 | 258 xi=updateq(x,in,xi,L); |
4171
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
259 in+=nch; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
260 if(!--i){ |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
261 // Run the FIR filter |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
262 FIR((&x[xi]),(&pl_resample.w[wi*L]),out); |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
263 len++; out+=nch; |
3631 | 264 |
4171
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
265 // Update wi to point at the correct polyphase component |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
266 wi=(wi+dn)%up; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
267 |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
268 // Insert i number of new samples in queue |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
269 i = inc; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
270 if(wi<level) i++; |
585f0c77d8f5
Sync problem when using fractional resampling fixed + speed increased.
anders
parents:
4049
diff
changeset
|
271 } |
3631 | 272 } |
273 } | |
274 // Save values that needs to be kept for next time | |
275 pwi = wi; | |
276 pxi = xi; | |
277 pi = i; | |
278 // Set new data | |
279 ao_plugin_data.len=len*2; | |
280 ao_plugin_data.data=pl_resample.data; | |
281 return 1; | |
282 } |