Home | History | Annotate | Download | only in resampler_tools
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      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>
     19 #include <unistd.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 
     23 static double sinc(double x) {
     24     if (fabs(x) == 0.0f) return 1.0f;
     25     return sin(x) / x;
     26 }
     27 
     28 static double sqr(double x) {
     29     return x*x;
     30 }
     31 
     32 static 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
     40                 +y*(0.2659732+y*(0.360768e-1+y*0.45813e-2)))));
     41     } else {
     42         y=3.75/ax;
     43         ans=(exp(ax)/sqrt(ax))*(0.39894228+y*(0.1328592e-1
     44                 +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))))))));
     47     }
     48     return ans;
     49 }
     50 
     51 static double kaiser(int k, int N, double beta) {
     52     if (k < 0 || k > N)
     53         return 0;
     54     return I0(beta * sqrt(1.0 - sqr((2.0*k)/N - 1.0))) / I0(beta);
     55 }
     56 
     57 
     58 static 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);
     75 }
     76 
     77 int main(int argc, char** argv)
     78 {
     79     // nc is the number of bits to store the coefficients
     80     const int nc = 32;
     81 
     82     bool polyphase = false;
     83     unsigned int polyM = 160;
     84     unsigned int polyN = 147;
     85     bool debug = false;
     86     double Fs = 48000;
     87     double Fc = 20478;
     88     double atten = 1;
     89     int format = 0;
     90 
     91 
     92     // 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     //
    116     //    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
    124     double beta = 7.865;
    125 
    126 
    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)
    198     const int M = (1 << nz);
    199     const int N = M * nzc;
    200 
    201     // generate the right half of the filter
    202     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");
    221     }
    222 
    223     if (!polyphase) {
    224         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;
    230 
    231                 if (!debug) {
    232                     if (j == 0)
    233                         printf("\n    ");
    234                 }
    235 
    236                 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                 }
    243             }
    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);
    254                 double y = kaiser(i+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;;
    255                 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) {
    273         printf("\n};");
    274     }
    275     printf("\n");
    276     return 0;
    277 }
    278 
    279 // http://www.csee.umbc.edu/help/sound/AFsp-V2R1/html/audio/ResampAudio.html
    280 
    281 
    282