Mercurial > mplayer.hg
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 |