1 /*=============================================================================
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.
6 // Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
8 //=============================================================================
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
23 #include "audio_out.h"
24 #include "audio_plugin.h"
25 #include "audio_plugin_internal.h"
28 static ao_info_t info
=
30 "Sample frequency conversion audio plugin",
36 LIBAO_PLUGIN_EXTERN(resample
)
38 #define min(a,b) (((a) < (b)) ? (a) : (b))
39 #define max(a,b) (((a) > (b)) ? (a) : (b))
41 /* Below definition selects the length of each poly phase component.
42 Valid definitions are L8 and L16, where the number denotes the
43 length of the filter. This definition affects the computational
44 complexity (see play()), the performance (see filter.h) and the
45 memory usage. The filterlenght is choosen to 8 if the machine is
46 slow and to 16 if the machine is fast and has MMX.
49 #if !defined(HAVE_SSE) && !defined(HAVE_3DNOW) //This machine is slow
51 #define W W8 // Filter bank parameters
52 #define L 8 // Filter length
54 #define FIR(x,w,y) *y=(int16_t)firn(x,w,8);
56 // Unrolled loop to speed up execution
58 int16_t a = (w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3]) >> 16; \
59 int16_t b = (w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7]) >> 16; \
64 #else /* Fast machine */
68 #define FIR(x,w,y) *y=(int16_t)firn(x,w,16);
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? */
81 typedef struct pl_resample_s
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 int16_t ws
[UP
*L
]; // List of all available filters
90 int16_t xs
[CH
][L
*2]; // Circular buffers
93 static pl_resample_t pl_resample
= {NULL
,NULL
,1,1,1,0,W
};
95 // to set/get/query special features/parameters
96 static int control(int cmd
,void *arg
){
98 case AOCONTROL_PLUGIN_SET_LEN
:
100 free(pl_resample
.data
);
101 pl_resample
.len
= ao_plugin_data
.len
;
102 pl_resample
.data
=(int16_t*)malloc(pl_resample
.len
);
103 if(!pl_resample
.data
)
104 return CONTROL_ERROR
;
105 ao_plugin_data
.len
= (int)((double)ao_plugin_data
.len
*
106 ((double)pl_resample
.dn
)/
107 ((double)pl_resample
.up
));
113 // open & setup audio device
114 // return: 1=success 0=fail
116 int fin
=ao_plugin_data
.rate
;
117 int fout
=ao_plugin_cfg
.pl_resample_fout
;
118 pl_resample
.w
=pl_resample
.ws
;
121 // Sheck input format
122 if(ao_plugin_data
.format
!= AFMT_S16_NE
){
123 fprintf(stderr
,"[pl_resample] Input audio format not yet suported. \n");
126 // Sanity check and calculate down sampling factor
127 if((float)max(fin
,fout
)/(float)min(fin
,fout
) > 10){
128 fprintf(stderr
,"[pl_resample] The difference between fin and fout is too large.\n");
131 pl_resample
.dn
=(int)(0.5+((float)(fin
*pl_resample
.up
))/((float)fout
));
133 pl_resample
.channels
=ao_plugin_data
.channels
;
134 if(ao_plugin_data
.channels
>CH
){
135 fprintf(stderr
,"[pl_resample] Too many channels, max is 6.\n");
139 // Tell the world what we are up to
140 printf("[pl_resample] Up=%i, Down=%i, True fout=%f\n",
141 pl_resample
.up
,pl_resample
.dn
,
142 ((float)fin
*pl_resample
.up
)/((float)pl_resample
.dn
));
144 // This plugin changes buffersize and adds some delay
145 ao_plugin_data
.sz_mult
/=((float)pl_resample
.up
)/((float)pl_resample
.dn
);
146 ao_plugin_data
.delay_fix
-= ((float)L
/2) * (1/fout
);
147 ao_plugin_data
.rate
=fout
;
152 static void uninit(){
154 free(pl_resample
.data
);
155 pl_resample
.data
=NULL
;
162 /* forward declarations */
166 // processes 'ao_plugin_data.len' bytes of 'data'
167 // called for every block of data
168 // FIXME: this routine needs to be optimized (it is probably possible to do a lot here)
170 if(pl_resample
.up
==pl_resample
.dn
){
171 register int16_t* in
= ((int16_t*)ao_plugin_data
.data
);
172 register int16_t* end
= in
+ao_plugin_data
.len
/2;
173 while(in
< end
) *(in
++)>>=1;
176 if(pl_resample
.up
>pl_resample
.dn
)
178 // if(pl_resample.up<pl_resample.dn)
183 static uint16_t pwi
= 0; // Index for w
184 static uint16_t pxi
= 0; // Index for circular queue
186 uint16_t ci
= pl_resample
.channels
; // Index for channels
187 uint16_t nch
= pl_resample
.channels
; // Number of channels
188 uint16_t len
= 0; // Number of input samples
189 uint16_t inc
= pl_resample
.up
/pl_resample
.dn
;
190 uint16_t level
= pl_resample
.up
%pl_resample
.dn
;
191 uint16_t up
= pl_resample
.up
;
192 uint16_t dn
= pl_resample
.dn
;
194 register int16_t* w
= pl_resample
.w
;
195 register uint16_t wi
,xi
; // Temporary indexes
197 // Index current channel
199 // Temporary pointers
200 register int16_t* x
= pl_resample
.xs
[ci
];
201 register int16_t* in
= ((int16_t*)ao_plugin_data
.data
)+ci
;
202 register int16_t* out
= pl_resample
.data
+ci
;
203 int16_t* end
= in
+ao_plugin_data
.len
/2; // Block loop end
208 register uint16_t i
= inc
;
211 xi
=updateq(x
,in
,xi
,L
);
214 // Run the FIR filter
215 FIR((&x
[xi
]),(&w
[wi
*L
]),out
);
217 // Update wi to point at the correct polyphase component
223 // Save values that needs to be kept for next time
228 ao_plugin_data
.len
=len
*2;
229 ao_plugin_data
.data
=pl_resample
.data
;
234 static uint16_t pwi
= 0; // Index for w
235 static uint16_t pxi
= 0; // Index for circular queue
236 static uint16_t pi
= 1; // Number of new samples to put in x queue
238 uint16_t ci
= pl_resample
.channels
; // Index for channels
239 uint16_t len
= 0; // Number of input samples
240 uint16_t nch
= pl_resample
.channels
; // Number of channels
241 uint16_t inc
= pl_resample
.dn
/pl_resample
.up
;
242 uint16_t level
= pl_resample
.dn
%pl_resample
.up
;
243 uint16_t up
= pl_resample
.up
;
244 uint16_t dn
= pl_resample
.dn
;
246 register uint16_t i
,wi
,xi
; // Temporary indexes
249 // Index current channel
251 // Temporary pointers
252 register int16_t* x
= pl_resample
.xs
[ci
];
253 register int16_t* in
= ((int16_t*)ao_plugin_data
.data
)+ci
;
254 register int16_t* out
= pl_resample
.data
+ci
;
256 register int16_t* end
= in
+ao_plugin_data
.len
/2;
257 i
= pi
; wi
= pwi
; xi
= pxi
;
261 xi
=updateq(x
,in
,xi
,L
);
264 // Run the FIR filter
265 FIR((&x
[xi
]),(&pl_resample
.w
[wi
*L
]),out
);
268 // Update wi to point at the correct polyphase component
271 // Insert i number of new samples in queue
277 // Save values that needs to be kept for next time
282 ao_plugin_data
.len
=len
*2;
283 ao_plugin_data
.data
=pl_resample
.data
;