2 * Sinc interpolator coefficient and delta generator for the OpenAL Soft
3 * cross platform audio library.
5 * Copyright (C) 2015 by Christopher Fitzgerald.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * Or visit: http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html
24 * --------------------------------------------------------------------------
26 * This is a modified version of the bandlimited windowed sinc interpolator
27 * algorithm presented here:
29 * Smith, J.O. "Windowed Sinc Interpolation", in
30 * Physical Audio Signal Processing,
31 * https://ccrma.stanford.edu/~jos/pasp/Windowed_Sinc_Interpolation.html,
33 * accessed October 2012.
41 #define M_PI (3.14159265358979323846)
44 // The number of distinct scale and phase intervals within the filter table.
45 #define BSINC_SCALE_COUNT (16)
46 #define BSINC_PHASE_COUNT (16)
48 #define BSINC_REJECTION (60.0)
49 #define BSINC_POINTS_MIN (12)
51 static double MinDouble(double a
, double b
)
52 { return (a
<= b
) ? a
: b
; }
54 static double MaxDouble(double a
, double b
)
55 { return (a
>= b
) ? a
: b
; }
57 /* NOTE: This is the normalized (instead of just sin(x)/x) cardinal sine
60 * f_t -- normalized transition frequency (0.5 is nyquist)
61 * x -- sample index (-N to N)
63 static double Sinc(const double x
)
67 return sin(M_PI
* x
) / (M_PI
* x
);
70 static double BesselI_0(const double x
)
72 double term
, sum
, last_sum
, x2
, y
;
86 } while(sum
!= last_sum
);
91 /* NOTE: k is assumed normalized (-1 to 1)
92 * beta is equivalent to 2 alpha
94 static double Kaiser(const double b
, const double k
)
98 if((k
< -1.0) || (k
> 1.0))
101 k2
= MaxDouble(1.0 - (k
* k
), 0.0);
103 return BesselI_0(b
* sqrt(k2
)) / BesselI_0(b
);
106 /* NOTE: Calculates the transition width of the Kaiser window. Rejection is
109 static double CalcKaiserWidth(const double rejection
, const int order
)
111 double w_t
= 2.0 * M_PI
;
114 return (rejection
- 7.95) / (order
* 2.285 * w_t
);
116 return 5.79 / (order
* w_t
);
119 static double CalcKaiserBeta(const double rejection
)
122 return 0.1102 * (rejection
- 8.7);
123 else if(rejection
>= 21.0)
124 return (0.5842 * pow(rejection
- 21.0, 0.4)) +
125 (0.07886 * (rejection
- 21.0));
129 /* Generates the coefficient, delta, and index tables required by the bsinc resampler */
130 static void BsiGenerateTables()
132 static double filter
[BSINC_SCALE_COUNT
][BSINC_PHASE_COUNT
+ 1][2 * BSINC_POINTS_MIN
];
133 static double scDeltas
[BSINC_SCALE_COUNT
- 1][BSINC_PHASE_COUNT
][2 * BSINC_POINTS_MIN
];
134 static double phDeltas
[BSINC_SCALE_COUNT
][BSINC_PHASE_COUNT
+ 1][2 * BSINC_POINTS_MIN
];
135 static double spDeltas
[BSINC_SCALE_COUNT
- 1][BSINC_PHASE_COUNT
][2 * BSINC_POINTS_MIN
];
136 static int mt
[BSINC_SCALE_COUNT
];
137 static double at
[BSINC_SCALE_COUNT
];
138 double width
, beta
, scaleBase
, scaleRange
;
141 memset(filter
, 0, sizeof(filter
));
142 memset(scDeltas
, 0, sizeof(scDeltas
));
143 memset(phDeltas
, 0, sizeof(phDeltas
));
144 memset(spDeltas
, 0, sizeof(spDeltas
));
146 /* Calculate windowing parameters. The width describes the transition
147 band, but it may vary due to the linear interpolation between scales
150 width
= CalcKaiserWidth(BSINC_REJECTION
, BSINC_POINTS_MIN
);
151 beta
= CalcKaiserBeta(BSINC_REJECTION
);
152 scaleBase
= width
/ 2.0;
153 scaleRange
= 1.0 - scaleBase
;
155 // Determine filter scaling.
156 for(si
= 0; si
< BSINC_SCALE_COUNT
; si
++)
158 const double scale
= scaleBase
+ (scaleRange
* si
/ (BSINC_SCALE_COUNT
- 1));
159 const double a
= MinDouble(BSINC_POINTS_MIN
, BSINC_POINTS_MIN
/ (2.0 * scale
));
160 int m
= 2 * (int)floor(a
);
162 // Make sure the number of points is a multiple of 4 (for SSE).
169 /* Calculate the Kaiser-windowed Sinc filter coefficients for each scale
172 for(si
= 0; si
< BSINC_SCALE_COUNT
; si
++)
174 const int m
= mt
[si
];
175 const int o
= BSINC_POINTS_MIN
- (m
/ 2);
176 const int l
= (m
/ 2) - 1;
177 const double a
= at
[si
];
178 const double scale
= scaleBase
+ (scaleRange
* si
/ (BSINC_SCALE_COUNT
- 1));
179 const double cutoff
= (0.5 * scale
) - (scaleBase
* MaxDouble(0.5, scale
));
181 for(pi
= 0; pi
<= BSINC_PHASE_COUNT
; pi
++)
183 const double phase
= l
+ ((double)pi
/ BSINC_PHASE_COUNT
);
185 for(i
= 0; i
< m
; i
++)
187 const double x
= i
- phase
;
188 filter
[si
][pi
][o
+ i
] = Kaiser(beta
, x
/ a
) * 2.0 * cutoff
* Sinc(2.0 * cutoff
* x
);
193 /* Linear interpolation between scales is simplified by pre-calculating
194 the delta (b - a) in: x = a + f (b - a)
196 Given a difference in points between scales, the destination points
197 will be 0, thus: x = a + f (-a)
199 for(si
= 0; si
< (BSINC_SCALE_COUNT
- 1); si
++)
201 const int m
= mt
[si
];
202 const int o
= BSINC_POINTS_MIN
- (m
/ 2);
204 for(pi
= 0; pi
< BSINC_PHASE_COUNT
; pi
++)
206 for(i
= 0; i
< m
; i
++)
207 scDeltas
[si
][pi
][o
+ i
] = filter
[si
+ 1][pi
][o
+ i
] - filter
[si
][pi
][o
+ i
];
211 // Linear interpolation between phases is also simplified.
212 for(si
= 0; si
< BSINC_SCALE_COUNT
; si
++)
214 const int m
= mt
[si
];
215 const int o
= BSINC_POINTS_MIN
- (m
/ 2);
217 for(pi
= 0; pi
< BSINC_PHASE_COUNT
; pi
++)
219 for(i
= 0; i
< m
; i
++)
220 phDeltas
[si
][pi
][o
+ i
] = filter
[si
][pi
+ 1][o
+ i
] - filter
[si
][pi
][o
+ i
];
224 /* This last simplification is done to complete the bilinear equation for
225 the combination of scale and phase.
227 for(si
= 0; si
< (BSINC_SCALE_COUNT
- 1); si
++)
229 const int m
= mt
[si
];
230 const int o
= BSINC_POINTS_MIN
- (m
/ 2);
232 for(pi
= 0; pi
< BSINC_PHASE_COUNT
; pi
++)
234 for(i
= 0; i
< m
; i
++)
235 spDeltas
[si
][pi
][o
+ i
] = phDeltas
[si
+ 1][pi
][o
+ i
] - phDeltas
[si
][pi
][o
+ i
];
239 // Calculate the table size.
241 for(si
= 1; si
< BSINC_SCALE_COUNT
; si
++)
242 i
+= BSINC_PHASE_COUNT
* mt
[si
];
243 for(si
= 0; si
< (BSINC_SCALE_COUNT
- 1); si
++)
244 i
+= 2 * BSINC_PHASE_COUNT
* mt
[si
];
245 for(si
= 1; si
< BSINC_SCALE_COUNT
; si
++)
246 i
+= BSINC_PHASE_COUNT
* mt
[si
];
248 fprintf(stdout
, "static const float bsincTab[%d] =\n{\n", i
);
250 /* Only output enough coefficients for the first (cut) scale as needed to
251 perform interpolation without extra branching.
253 fprintf(stdout
, " /* %2d,%2d */", mt
[0], 0);
254 for(i
= 0; i
< mt
[0]; i
++)
255 fprintf(stdout
, " %+14.9ef,", filter
[0][0][i
]);
256 fprintf(stdout
, "\n\n");
258 for(si
= 1; si
< BSINC_SCALE_COUNT
; si
++)
260 const int m
= mt
[si
];
261 const int o
= BSINC_POINTS_MIN
- (m
/ 2);
263 for(pi
= 0; pi
< BSINC_PHASE_COUNT
; pi
++)
265 fprintf(stdout
, " /* %2d,%2d */", m
, pi
);
266 for(i
= 0; i
< m
; i
++)
267 fprintf(stdout
, " %+14.9ef,", filter
[si
][pi
][o
+ i
]);
268 fprintf(stdout
, "\n");
271 fprintf(stdout
, "\n");
273 // There are N-1 scale deltas for N scales.
274 for(si
= 0; si
< (BSINC_SCALE_COUNT
- 1); si
++)
276 const int m
= mt
[si
];
277 const int o
= BSINC_POINTS_MIN
- (m
/ 2);
279 for(pi
= 0; pi
< BSINC_PHASE_COUNT
; pi
++)
281 fprintf(stdout
, " /* %2d,%2d */", m
, pi
);
282 for(i
= 0; i
< m
; i
++)
283 fprintf(stdout
, " %+14.9ef,", scDeltas
[si
][pi
][o
+ i
]);
284 fprintf(stdout
, "\n");
287 fprintf(stdout
, "\n");
289 // Exclude phases for the first (cut) scale.
290 for(si
= 1; si
< BSINC_SCALE_COUNT
; si
++)
292 const int m
= mt
[si
];
293 const int o
= BSINC_POINTS_MIN
- (m
/ 2);
295 for(pi
= 0; pi
< BSINC_PHASE_COUNT
; pi
++)
297 fprintf(stdout
, " /* %2d,%2d */", m
, pi
);
298 for(i
= 0; i
< m
; i
++)
299 fprintf(stdout
, " %+14.9ef,", phDeltas
[si
][pi
][o
+ i
]);
300 fprintf(stdout
, "\n");
303 fprintf(stdout
, "\n");
305 for(si
= 0; si
< (BSINC_SCALE_COUNT
- 1); si
++)
307 const int m
= mt
[si
];
308 const int o
= BSINC_POINTS_MIN
- (m
/ 2);
310 for(pi
= 0; pi
< BSINC_PHASE_COUNT
; pi
++)
312 fprintf(stdout
, " /* %2d,%2d */", m
, pi
);
313 for(i
= 0; i
< m
; i
++)
314 fprintf(stdout
, " %+14.9ef,", spDeltas
[si
][pi
][o
+ i
]);
315 fprintf(stdout
, "\n");
318 fprintf(stdout
, "};\n\n");
320 /* The scaleBase is calculated from the Kaiser window transition width.
321 It represents the absolute limit to the filter before it fully cuts
322 the signal. The limit in octaves can be calculated by taking the
323 base-2 logarithm of its inverse: log_2(1 / scaleBase)
325 fprintf(stdout
, " static const ALfloat scaleBase = %.9ef, scaleRange = %.9ef;\n", scaleBase
, 1.0 / scaleRange
);
326 fprintf(stdout
, " static const ALuint m[BSINC_SCALE_COUNT] = {");
328 fprintf(stdout
, " %d", mt
[0]);
329 for(si
= 1; si
< BSINC_SCALE_COUNT
; si
++)
330 fprintf(stdout
, ", %d", mt
[si
]);
332 fprintf(stdout
, " };\n");
333 fprintf(stdout
, " static const ALuint to[4][BSINC_SCALE_COUNT] =\n {\n { 0");
336 for(si
= 1; si
< BSINC_SCALE_COUNT
; si
++)
338 fprintf(stdout
, ", %d", i
);
339 i
+= BSINC_PHASE_COUNT
* mt
[si
];
341 fprintf(stdout
, " },\n {");
342 for(si
= 0; si
< (BSINC_SCALE_COUNT
- 1); si
++)
344 fprintf(stdout
, " %d,", i
);
345 i
+= BSINC_PHASE_COUNT
* mt
[si
];
347 fprintf(stdout
, " 0 },\n { 0");
348 for(si
= 1; si
< BSINC_SCALE_COUNT
; si
++)
350 fprintf(stdout
, ", %d", i
);
351 i
+= BSINC_PHASE_COUNT
* mt
[si
];
353 fprintf (stdout
, " },\n {");
354 for(si
= 0; si
< (BSINC_SCALE_COUNT
- 1); si
++)
356 fprintf(stdout
, " %d,", i
);
357 i
+= BSINC_PHASE_COUNT
* mt
[si
];
359 fprintf(stdout
, " 0 }\n };\n");
361 fprintf(stdout
, " static const ALuint tm[2][BSINC_SCALE_COUNT] = \n {\n { 0");
362 for(si
= 1; si
< BSINC_SCALE_COUNT
; si
++)
363 fprintf(stdout
, ", %d", mt
[si
]);
364 fprintf(stdout
, " },\n {");
365 for(si
= 0; si
< (BSINC_SCALE_COUNT
- 1); si
++)
366 fprintf(stdout
, " %d,", mt
[si
]);
367 fprintf(stdout
, " 0 }\n };\n");