blob: fe4d212d161178c49ae76cde52b3914646d8e49c [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
Andy Hung86eae0e2013-12-09 12:12:46 -080023static inline double sinc(double x) {
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070024 if (fabs(x) == 0.0f) return 1.0f;
25 return sin(x) / x;
26}
27
Andy Hung86eae0e2013-12-09 12:12:46 -080028static inline double sqr(double x) {
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070029 return x*x;
30}
31
Andy Hung86eae0e2013-12-09 12:12:46 -080032static inline int64_t toint(double x, int64_t maxval) {
33 int64_t v;
34
Andy Hung523476a2013-12-30 10:34:29 -080035 v = static_cast<int64_t>(floor(x * maxval + 0.5));
Andy Hung86eae0e2013-12-09 12:12:46 -080036 if (v >= maxval) {
37 return maxval - 1; // error!
38 }
39 return v;
40}
41
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070042static double I0(double x) {
43 // from the Numerical Recipes in C p. 237
44 double ax,ans,y;
45 ax=fabs(x);
46 if (ax < 3.75) {
47 y=x/3.75;
48 y*=y;
49 ans=1.0+y*(3.5156229+y*(3.0899424+y*(1.2067492
Pixelflinger73e90262012-10-25 19:43:49 -070050 +y*(0.2659732+y*(0.360768e-1+y*0.45813e-2)))));
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070051 } else {
52 y=3.75/ax;
53 ans=(exp(ax)/sqrt(ax))*(0.39894228+y*(0.1328592e-1
Pixelflinger73e90262012-10-25 19:43:49 -070054 +y*(0.225319e-2+y*(-0.157565e-2+y*(0.916281e-2
55 +y*(-0.2057706e-1+y*(0.2635537e-1+y*(-0.1647633e-1
56 +y*0.392377e-2))))))));
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070057 }
58 return ans;
59}
60
Pixelflinger73e90262012-10-25 19:43:49 -070061static double kaiser(int k, int N, double beta) {
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070062 if (k < 0 || k > N)
63 return 0;
Pixelflinger73e90262012-10-25 19:43:49 -070064 return I0(beta * sqrt(1.0 - sqr((2.0*k)/N - 1.0))) / I0(beta);
65}
66
Pixelflinger73e90262012-10-25 19:43:49 -070067static void usage(char* name) {
68 fprintf(stderr,
Glenn Kasten6506d192015-02-17 14:52:25 -080069 "usage: %s [-h] [-d] [-D] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
Andy Hung86eae0e2013-12-09 12:12:46 -080070 " [-f {float|fixed|fixed16}] [-b beta] [-v dBFS] [-l lerp]\n"
Glenn Kasten6506d192015-02-17 14:52:25 -080071 " %s [-h] [-d] [-D] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
Andy Hung86eae0e2013-12-09 12:12:46 -080072 " [-f {float|fixed|fixed16}] [-b beta] [-v dBFS] -p M/N\n"
Pixelflinger73e90262012-10-25 19:43:49 -070073 " -h this help message\n"
74 " -d debug, print comma-separated coefficient table\n"
Glenn Kasten6506d192015-02-17 14:52:25 -080075 " -D generate extra declarations\n"
Pixelflinger73e90262012-10-25 19:43:49 -070076 " -p generate poly-phase filter coefficients, with sample increment M/N\n"
77 " -s sample rate (48000)\n"
78 " -c cut-off frequency (20478)\n"
79 " -n number of zero-crossings on one side (8)\n"
80 " -l number of lerping bits (4)\n"
Andy Hung86eae0e2013-12-09 12:12:46 -080081 " -m number of polyphases (related to -l, default 16)\n"
Glenn Kasten904e9822015-02-17 14:50:44 -080082 " -f output format, can be fixed, fixed16, or float (fixed)\n"
Pixelflinger73e90262012-10-25 19:43:49 -070083 " -b kaiser window parameter beta (7.865 [-80dB])\n"
84 " -v attenuation in dBFS (0)\n",
85 name, name
86 );
87 exit(0);
Mathias Agopian4b8a3d82007-08-23 03:16:02 -070088}
89
90int main(int argc, char** argv)
91{
92 // nc is the number of bits to store the coefficients
Andy Hung86eae0e2013-12-09 12:12:46 -080093 int nc = 32;
Pixelflinger73e90262012-10-25 19:43:49 -070094 bool polyphase = false;
95 unsigned int polyM = 160;
96 unsigned int polyN = 147;
97 bool debug = false;
98 double Fs = 48000;
Mathias Agopianb4b75b42012-10-29 17:13:20 -070099 double Fc = 20478;
Pixelflinger73e90262012-10-25 19:43:49 -0700100 double atten = 1;
Glenn Kasten6506d192015-02-17 14:52:25 -0800101 int format = 0; // 0=fixed, 1=float
Glenn Kastenbf5d0662015-03-02 11:22:06 -0800102 bool declarations = false;
Mathias Agopian4b8a3d82007-08-23 03:16:02 -0700103
Pixelflinger73e90262012-10-25 19:43:49 -0700104 // in order to keep the errors associated with the linear
105 // interpolation of the coefficients below the quantization error
106 // we must satisfy:
107 // 2^nz >= 2^(nc/2)
108 //
109 // for 16 bit coefficients that would be 256
110 //
111 // note that increasing nz only increases memory requirements,
112 // but doesn't increase the amount of computation to do.
113 //
114 //
115 // see:
116 // Smith, J.O. Digital Audio Resampling Home Page
117 // https://ccrma.stanford.edu/~jos/resample/, 2011-03-29
118 //
Pixelflinger73e90262012-10-25 19:43:49 -0700119
120 // | 0.1102*(A - 8.7) A > 50
121 // beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21) 21 <= A <= 50
122 // | 0 A < 21
123 // with A is the desired stop-band attenuation in dBFS
124 //
125 // for eg:
126 //
Mathias Agopian2a967b32007-10-29 04:34:36 -0700127 // 30 dB 2.210
128 // 40 dB 3.384
129 // 50 dB 4.538
130 // 60 dB 5.658
131 // 70 dB 6.764
132 // 80 dB 7.865
133 // 90 dB 8.960
134 // 100 dB 10.056
Pixelflinger73e90262012-10-25 19:43:49 -0700135 double beta = 7.865;
Mathias Agopian2a967b32007-10-29 04:34:36 -0700136
Pixelflinger73e90262012-10-25 19:43:49 -0700137 // 2*nzc = (A - 8) / (2.285 * dw)
138 // with dw the transition width = 2*pi*dF/Fs
139 //
140 int nzc = 8;
141
Glenn Kastena4ebf132014-03-10 12:09:26 -0700142 /*
143 * Example:
144 * 44.1 KHz to 48 KHz resampling
145 * 100 dB rejection above 28 KHz
146 * (the spectrum will fold around 24 KHz and we want 100 dB rejection
147 * at the point where the folding reaches 20 KHz)
148 * ...___|_____
149 * | \|
150 * | ____/|\____
151 * |/alias| \
152 * ------/------+------\---------> KHz
153 * 20 24 28
154 *
155 * Transition band 8 KHz, or dw = 1.0472
156 *
157 * beta = 10.056
158 * nzc = 20
159 */
Pixelflinger73e90262012-10-25 19:43:49 -0700160
Andy Hung86eae0e2013-12-09 12:12:46 -0800161 int M = 1 << 4; // number of phases for interpolation
Pixelflinger73e90262012-10-25 19:43:49 -0700162 int ch;
Glenn Kasten6506d192015-02-17 14:52:25 -0800163 while ((ch = getopt(argc, argv, ":hds:c:n:f:l:m:b:p:v:z:D")) != -1) {
Pixelflinger73e90262012-10-25 19:43:49 -0700164 switch (ch) {
165 case 'd':
166 debug = true;
167 break;
Glenn Kasten6506d192015-02-17 14:52:25 -0800168 case 'D':
169 declarations = true;
170 break;
Pixelflinger73e90262012-10-25 19:43:49 -0700171 case 'p':
172 if (sscanf(optarg, "%u/%u", &polyM, &polyN) != 2) {
173 usage(argv[0]);
174 }
175 polyphase = true;
176 break;
177 case 's':
178 Fs = atof(optarg);
179 break;
180 case 'c':
181 Fc = atof(optarg);
182 break;
183 case 'n':
184 nzc = atoi(optarg);
185 break;
Andy Hung86eae0e2013-12-09 12:12:46 -0800186 case 'm':
187 M = atoi(optarg);
188 break;
Pixelflinger73e90262012-10-25 19:43:49 -0700189 case 'l':
Andy Hung86eae0e2013-12-09 12:12:46 -0800190 M = 1 << atoi(optarg);
Pixelflinger73e90262012-10-25 19:43:49 -0700191 break;
192 case 'f':
Andy Hung86eae0e2013-12-09 12:12:46 -0800193 if (!strcmp(optarg, "fixed")) {
194 format = 0;
195 }
196 else if (!strcmp(optarg, "fixed16")) {
197 format = 0;
198 nc = 16;
199 }
200 else if (!strcmp(optarg, "float")) {
201 format = 1;
202 }
203 else {
204 usage(argv[0]);
205 }
Pixelflinger73e90262012-10-25 19:43:49 -0700206 break;
207 case 'b':
208 beta = atof(optarg);
209 break;
210 case 'v':
211 atten = pow(10, -fabs(atof(optarg))*0.05 );
212 break;
213 case 'h':
214 default:
215 usage(argv[0]);
216 break;
217 }
218 }
219
220 // cut off frequency ratio Fc/Fs
221 double Fcr = Fc / Fs;
222
Pixelflinger73e90262012-10-25 19:43:49 -0700223 // total number of coefficients (one side)
Andy Hung86eae0e2013-12-09 12:12:46 -0800224
Mathias Agopian46afbec2012-11-04 02:03:49 -0800225 const int N = M * nzc;
Mathias Agopian4b8a3d82007-08-23 03:16:02 -0700226
Andy Hung86eae0e2013-12-09 12:12:46 -0800227 // lerp (which is most useful if M is a power of 2)
228
229 int nz = 0; // recalculate nz as the bits needed to represent M
230 for (int i = M-1 ; i; i>>=1, nz++);
Mathias Agopian4b8a3d82007-08-23 03:16:02 -0700231 // generate the right half of the filter
Pixelflinger73e90262012-10-25 19:43:49 -0700232 if (!debug) {
Glenn Kastenbf5d0662015-03-02 11:22:06 -0800233 printf("// cmd-line:");
Glenn Kasten393d4d22015-02-17 14:53:30 -0800234 for (int i=0 ; i<argc ; i++) {
Glenn Kastenbf5d0662015-03-02 11:22:06 -0800235 printf(" %s", argv[i]);
Pixelflinger73e90262012-10-25 19:43:49 -0700236 }
237 printf("\n");
Glenn Kasten6506d192015-02-17 14:52:25 -0800238 if (declarations) {
239 if (!polyphase) {
240 printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", N);
241 printf("const int32_t RESAMPLE_FIR_INT_PHASES = %d;\n", M);
242 printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", nzc);
243 } else {
244 printf("const int32_t RESAMPLE_FIR_SIZE = %d;\n", 2*nzc*polyN);
245 printf("const int32_t RESAMPLE_FIR_NUM_COEF = %d;\n", 2*nzc);
246 }
247 if (!format) {
248 printf("const int32_t RESAMPLE_FIR_COEF_BITS = %d;\n", nc);
249 }
250 printf("\n");
251 printf("static %s resampleFIR[] = {", !format ? "int32_t" : "float");
Pixelflinger73e90262012-10-25 19:43:49 -0700252 }
Mathias Agopian4b8a3d82007-08-23 03:16:02 -0700253 }
Mathias Agopian2a967b32007-10-29 04:34:36 -0700254
Pixelflinger73e90262012-10-25 19:43:49 -0700255 if (!polyphase) {
Mathias Agopian46afbec2012-11-04 02:03:49 -0800256 for (int i=0 ; i<=M ; i++) { // an extra set of coefs for interpolation
257 for (int j=0 ; j<nzc ; j++) {
258 int ix = j*M + i;
Andy Hung86eae0e2013-12-09 12:12:46 -0800259 double x = (2.0 * M_PI * ix * Fcr) / M;
Mathias Agopian46afbec2012-11-04 02:03:49 -0800260 double y = kaiser(ix+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;
261 y *= atten;
Pixelflinger73e90262012-10-25 19:43:49 -0700262
Mathias Agopian46afbec2012-11-04 02:03:49 -0800263 if (!debug) {
264 if (j == 0)
Glenn Kastene1984fc2015-02-17 15:00:19 -0800265 printf("\n ");
Mathias Agopian46afbec2012-11-04 02:03:49 -0800266 }
Mathias Agopian46afbec2012-11-04 02:03:49 -0800267 if (!format) {
Andy Hung86eae0e2013-12-09 12:12:46 -0800268 int64_t yi = toint(y, 1ULL<<(nc-1));
269 if (nc > 16) {
Glenn Kasten9c380ac2015-02-17 14:54:09 -0800270 printf("0x%08x,", int32_t(yi));
Andy Hung86eae0e2013-12-09 12:12:46 -0800271 } else {
Glenn Kasten9c380ac2015-02-17 14:54:09 -0800272 printf("0x%04x,", int32_t(yi)&0xffff);
Andy Hung86eae0e2013-12-09 12:12:46 -0800273 }
Mathias Agopian46afbec2012-11-04 02:03:49 -0800274 } else {
Glenn Kasten9c380ac2015-02-17 14:54:09 -0800275 printf("%.9g%s", y, debug ? "," : "f,");
276 }
277 if (j != nzc-1) {
278 printf(" ");
Mathias Agopian46afbec2012-11-04 02:03:49 -0800279 }
Pixelflinger73e90262012-10-25 19:43:49 -0700280 }
281 }
282 } else {
Glenn Kastena4ebf132014-03-10 12:09:26 -0700283 for (unsigned int j=0 ; j<polyN ; j++) {
Pixelflinger73e90262012-10-25 19:43:49 -0700284 // calculate the phase
285 double p = ((polyM*j) % polyN) / double(polyN);
286 if (!debug) printf("\n ");
287 else printf("\n");
288 // generate a FIR per phase
289 for (int i=-nzc ; i<nzc ; i++) {
290 double x = 2.0 * M_PI * Fcr * (i + p);
Mathias Agopiand88a0512012-10-30 12:49:07 -0700291 double y = kaiser(i+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;;
Pixelflinger73e90262012-10-25 19:43:49 -0700292 y *= atten;
293 if (!format) {
Andy Hung86eae0e2013-12-09 12:12:46 -0800294 int64_t yi = toint(y, 1ULL<<(nc-1));
295 if (nc > 16) {
Glenn Kasten6506d192015-02-17 14:52:25 -0800296 printf("0x%08x,", int32_t(yi));
Andy Hung86eae0e2013-12-09 12:12:46 -0800297 } else {
Glenn Kasten6506d192015-02-17 14:52:25 -0800298 printf("0x%04x,", int32_t(yi)&0xffff);
Andy Hung86eae0e2013-12-09 12:12:46 -0800299 }
Pixelflinger73e90262012-10-25 19:43:49 -0700300 } else {
Glenn Kasten6506d192015-02-17 14:52:25 -0800301 printf("%.9g%s", y, debug ? "," : "f,");
Pixelflinger73e90262012-10-25 19:43:49 -0700302 }
303
Glenn Kasten6506d192015-02-17 14:52:25 -0800304 if (i != nzc-1) {
305 printf(" ");
Pixelflinger73e90262012-10-25 19:43:49 -0700306 }
307 }
308 }
309 }
310
Glenn Kasten6506d192015-02-17 14:52:25 -0800311 if (!debug && declarations) {
Pixelflinger73e90262012-10-25 19:43:49 -0700312 printf("\n};");
313 }
314 printf("\n");
315 return 0;
316}
317
Mathias Agopian2a967b32007-10-29 04:34:36 -0700318// http://www.csee.umbc.edu/help/sound/AFsp-V2R1/html/audio/ResampAudio.html