blob: cc3d509a43fb787200f15dabf1b5c55627da8f18 [file] [log] [blame]
Mathias Agopian4b8a3d82007-08-23 03:16:02 -07001/*
Dan Bornstein4cb4f7c2008-10-03 10:34:57 -07002 * Copyright (C) 2007 The Android Open Source Project
Mathias Agopian4b8a3d82007-08-23 03:16:02 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <math.h>
18#include <stdio.h>
Pixelflinger73e90262012-10-25 19:43:49 -070019#include <unistd.h>
20#include <stdlib.h>
21#include <string.h>
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070022
23static double sinc(double x) {
24 if (fabs(x) == 0.0f) return 1.0f;
25 return sin(x) / x;
26}
27
28static double sqr(double x) {
29 return x*x;
30}
31
32static double I0(double x) {
33 // from the Numerical Recipes in C p. 237
34 double ax,ans,y;
35 ax=fabs(x);
36 if (ax < 3.75) {
37 y=x/3.75;
38 y*=y;
39 ans=1.0+y*(3.5156229+y*(3.0899424+y*(1.2067492
Pixelflinger73e90262012-10-25 19:43:49 -070040 +y*(0.2659732+y*(0.360768e-1+y*0.45813e-2)))));
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070041 } else {
42 y=3.75/ax;
43 ans=(exp(ax)/sqrt(ax))*(0.39894228+y*(0.1328592e-1
Pixelflinger73e90262012-10-25 19:43:49 -070044 +y*(0.225319e-2+y*(-0.157565e-2+y*(0.916281e-2
45 +y*(-0.2057706e-1+y*(0.2635537e-1+y*(-0.1647633e-1
46 +y*0.392377e-2))))))));
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070047 }
48 return ans;
49}
50
Pixelflinger73e90262012-10-25 19:43:49 -070051static double kaiser(int k, int N, double beta) {
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070052 if (k < 0 || k > N)
53 return 0;
Pixelflinger73e90262012-10-25 19:43:49 -070054 return I0(beta * sqrt(1.0 - sqr((2.0*k)/N - 1.0))) / I0(beta);
55}
56
57
58static void usage(char* name) {
59 fprintf(stderr,
60 "usage: %s [-h] [-d] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings] [-f {float|fixed}] [-b beta] [-v dBFS] [-l lerp]\n"
61 " %s [-h] [-d] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings] [-f {float|fixed}] [-b beta] [-v dBFS] -p M/N\n"
62 " -h this help message\n"
63 " -d debug, print comma-separated coefficient table\n"
64 " -p generate poly-phase filter coefficients, with sample increment M/N\n"
65 " -s sample rate (48000)\n"
66 " -c cut-off frequency (20478)\n"
67 " -n number of zero-crossings on one side (8)\n"
68 " -l number of lerping bits (4)\n"
69 " -f output format, can be fixed-point or floating-point (fixed)\n"
70 " -b kaiser window parameter beta (7.865 [-80dB])\n"
71 " -v attenuation in dBFS (0)\n",
72 name, name
73 );
74 exit(0);
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070075}
76
77int main(int argc, char** argv)
78{
79 // nc is the number of bits to store the coefficients
Pixelflinger73e90262012-10-25 19:43:49 -070080 const int nc = 32;
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070081
Pixelflinger73e90262012-10-25 19:43:49 -070082 bool polyphase = false;
83 unsigned int polyM = 160;
84 unsigned int polyN = 147;
85 bool debug = false;
86 double Fs = 48000;
Mathias Agopianb4b75b42012-10-29 17:13:20 -070087 double Fc = 20478;
Pixelflinger73e90262012-10-25 19:43:49 -070088 double atten = 1;
89 int format = 0;
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070090
Mathias Agopian2a967b32007-10-29 04:34:36 -070091
Pixelflinger73e90262012-10-25 19:43:49 -070092 // in order to keep the errors associated with the linear
93 // interpolation of the coefficients below the quantization error
94 // we must satisfy:
95 // 2^nz >= 2^(nc/2)
96 //
97 // for 16 bit coefficients that would be 256
98 //
99 // note that increasing nz only increases memory requirements,
100 // but doesn't increase the amount of computation to do.
101 //
102 //
103 // see:
104 // Smith, J.O. Digital Audio Resampling Home Page
105 // https://ccrma.stanford.edu/~jos/resample/, 2011-03-29
106 //
107 int nz = 4;
108
109 // | 0.1102*(A - 8.7) A > 50
110 // beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21) 21 <= A <= 50
111 // | 0 A < 21
112 // with A is the desired stop-band attenuation in dBFS
113 //
114 // for eg:
115 //
Mathias Agopian2a967b32007-10-29 04:34:36 -0700116 // 30 dB 2.210
117 // 40 dB 3.384
118 // 50 dB 4.538
119 // 60 dB 5.658
120 // 70 dB 6.764
121 // 80 dB 7.865
122 // 90 dB 8.960
123 // 100 dB 10.056
Pixelflinger73e90262012-10-25 19:43:49 -0700124 double beta = 7.865;
Mathias Agopian2a967b32007-10-29 04:34:36 -0700125
Pixelflinger73e90262012-10-25 19:43:49 -0700126
127 // 2*nzc = (A - 8) / (2.285 * dw)
128 // with dw the transition width = 2*pi*dF/Fs
129 //
130 int nzc = 8;
131
132 //
133 // Example:
134 // 44.1 KHz to 48 KHz resampling
135 // 100 dB rejection above 28 KHz
136 // (the spectrum will fold around 24 KHz and we want 100 dB rejection
137 // at the point where the folding reaches 20 KHz)
138 // ...___|_____
139 // | \|
140 // | ____/|\____
141 // |/alias| \
142 // ------/------+------\---------> KHz
143 // 20 24 28
144
145 // Transition band 8 KHz, or dw = 1.0472
146 //
147 // beta = 10.056
148 // nzc = 20
149 //
150
151 int ch;
152 while ((ch = getopt(argc, argv, ":hds:c:n:f:l:b:p:v:")) != -1) {
153 switch (ch) {
154 case 'd':
155 debug = true;
156 break;
157 case 'p':
158 if (sscanf(optarg, "%u/%u", &polyM, &polyN) != 2) {
159 usage(argv[0]);
160 }
161 polyphase = true;
162 break;
163 case 's':
164 Fs = atof(optarg);
165 break;
166 case 'c':
167 Fc = atof(optarg);
168 break;
169 case 'n':
170 nzc = atoi(optarg);
171 break;
172 case 'l':
173 nz = atoi(optarg);
174 break;
175 case 'f':
176 if (!strcmp(optarg,"fixed")) format = 0;
177 else if (!strcmp(optarg,"float")) format = 1;
178 else usage(argv[0]);
179 break;
180 case 'b':
181 beta = atof(optarg);
182 break;
183 case 'v':
184 atten = pow(10, -fabs(atof(optarg))*0.05 );
185 break;
186 case 'h':
187 default:
188 usage(argv[0]);
189 break;
190 }
191 }
192
193 // cut off frequency ratio Fc/Fs
194 double Fcr = Fc / Fs;
195
196
197 // total number of coefficients (one side)
Mathias Agopian46afbec2012-11-04 02:03:49 -0800198 const int M = (1 << nz);
199 const int N = M * nzc;
Mathias Agopian4b8a3d82007-08-23 03:16:02 -0700200
201 // generate the right half of the filter
Pixelflinger73e90262012-10-25 19:43:49 -0700202 if (!debug) {
203 printf("// cmd-line: ");
204 for (int i=1 ; i<argc ; i++) {
205 printf("%s ", argv[i]);
206 }
207 printf("\n");
208 if (!polyphase) {
209 printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", N);
210 printf("const int32_t RESAMPLE_FIR_LERP_INT_BITS = %d;\n", nz);
211 printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", nzc);
212 } else {
213 printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", 2*nzc*polyN);
214 printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", 2*nzc);
215 }
216 if (!format) {
217 printf("const int32_t RESAMPLE_FIR_COEF_BITS = %d;\n", nc);
218 }
219 printf("\n");
220 printf("static %s resampleFIR[] = {", !format ? "int32_t" : "float");
Mathias Agopian4b8a3d82007-08-23 03:16:02 -0700221 }
Mathias Agopian2a967b32007-10-29 04:34:36 -0700222
Pixelflinger73e90262012-10-25 19:43:49 -0700223 if (!polyphase) {
Mathias Agopian46afbec2012-11-04 02:03:49 -0800224 for (int i=0 ; i<=M ; i++) { // an extra set of coefs for interpolation
225 for (int j=0 ; j<nzc ; j++) {
226 int ix = j*M + i;
227 double x = (2.0 * M_PI * ix * Fcr) / (1 << nz);
228 double y = kaiser(ix+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;
229 y *= atten;
Pixelflinger73e90262012-10-25 19:43:49 -0700230
Mathias Agopian46afbec2012-11-04 02:03:49 -0800231 if (!debug) {
232 if (j == 0)
233 printf("\n ");
234 }
Pixelflinger73e90262012-10-25 19:43:49 -0700235
Mathias Agopian46afbec2012-11-04 02:03:49 -0800236 if (!format) {
237 int64_t yi = floor(y * ((1ULL<<(nc-1))) + 0.5);
238 if (yi >= (1LL<<(nc-1))) yi = (1LL<<(nc-1))-1;
239 printf("0x%08x, ", int32_t(yi));
240 } else {
241 printf("%.9g%s ", y, debug ? "," : "f,");
242 }
Pixelflinger73e90262012-10-25 19:43:49 -0700243 }
244 }
245 } else {
246 for (int j=0 ; j<polyN ; j++) {
247 // calculate the phase
248 double p = ((polyM*j) % polyN) / double(polyN);
249 if (!debug) printf("\n ");
250 else printf("\n");
251 // generate a FIR per phase
252 for (int i=-nzc ; i<nzc ; i++) {
253 double x = 2.0 * M_PI * Fcr * (i + p);
Mathias Agopiand88a0512012-10-30 12:49:07 -0700254 double y = kaiser(i+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;;
Pixelflinger73e90262012-10-25 19:43:49 -0700255 y *= atten;
256 if (!format) {
257 int64_t yi = floor(y * ((1ULL<<(nc-1))) + 0.5);
258 if (yi >= (1LL<<(nc-1))) yi = (1LL<<(nc-1))-1;
259 printf("0x%08x", int32_t(yi));
260 } else {
261 printf("%.9g%s", y, debug ? "" : "f");
262 }
263
264 if (debug && (i==nzc-1)) {
265 } else {
266 printf(", ");
267 }
268 }
269 }
270 }
271
272 if (!debug) {
Pixelflinger73e90262012-10-25 19:43:49 -0700273 printf("\n};");
274 }
275 printf("\n");
276 return 0;
277}
278
Mathias Agopian2a967b32007-10-29 04:34:36 -0700279// http://www.csee.umbc.edu/help/sound/AFsp-V2R1/html/audio/ResampAudio.html
280
Pixelflinger73e90262012-10-25 19:43:49 -0700281