shithub: ft²

Download patch

ref: f62ba59953e3b01d9940ea42d3aa1d7aecc8494f
parent: 63fe6a3c1d5015d84eea470bcc77e1e74ab42f31
author: Olav Sørensen <olav.sorensen@live.no>
date: Sun Jan 12 12:11:28 EST 2025

Code cleanup

--- a/src/ft2_audio.c
+++ b/src/ft2_audio.c
@@ -191,17 +191,17 @@
 	// set sinc LUT pointers
 	if (config.interpolation == INTERPOLATION_SINC8)
 	{
-		fKaiserSinc = fKaiserSinc_8;
-		fDownSample1 = fDownSample1_8;
-		fDownSample2 = fDownSample2_8;
+		fSinc_1 = fSinc8_1;
+		fSinc_2 = fSinc8_2;
+		fSinc_3 = fSinc8_3;
 
 		audio.sincInterpolation = true;
 	}
 	else if (config.interpolation == INTERPOLATION_SINC16)
 	{
-		fKaiserSinc = fKaiserSinc_16;
-		fDownSample1 = fDownSample1_16;
-		fDownSample2 = fDownSample2_16;
+		fSinc_1 = fSinc16_1;
+		fSinc_2 = fSinc16_2;
+		fSinc_3 = fSinc16_3;
 
 		audio.sincInterpolation = true;
 	}
@@ -394,12 +394,12 @@
 			if (audio.sincInterpolation)
 			{
 				// decide which sinc LUT to use according to the resampling ratio
-				if (v->delta <= sincDownsample1Ratio)
-					v->fSincLUT = fKaiserSinc;
-				else if (v->delta <= sincDownsample2Ratio)
-					v->fSincLUT = fDownSample1;
+				if (v->delta <= sincRatio1)
+					v->fSincLUT = fSinc_1;
+				else if (v->delta <= sincRatio2)
+					v->fSincLUT = fSinc_2;
 				else
-					v->fSincLUT = fDownSample2;
+					v->fSincLUT = fSinc_3;
 			}
 		}
 
--- a/src/ft2_main.c
+++ b/src/ft2_main.c
@@ -147,7 +147,7 @@
 #ifdef __APPLE__
 	osxSetDirToProgramDirFromArgs(argv);
 #endif
-	if (!setupExecutablePath() || !loadBMPs() || !calcCubicSplineTables() || !calcWindowedSincTables())
+	if (!setupExecutablePath() || !loadBMPs() || !setupCubicSplineTables() || !setupWindowedSincTables())
 	{
 		cleanUpAndExit();
 		return 1;
--- a/src/mixer/ft2_cubic_spline.c
+++ b/src/mixer/ft2_cubic_spline.c
@@ -10,7 +10,7 @@
 
 float *f4PointCubicSplineLUT = NULL, *f6PointCubicSplineLUT = NULL; // globalized
 
-bool calcCubicSplineTables(void)
+bool setupCubicSplineTables(void)
 {
 	float *fPtr;
 
--- a/src/mixer/ft2_cubic_spline.h
+++ b/src/mixer/ft2_cubic_spline.h
@@ -4,16 +4,19 @@
 #include <stdbool.h>
 #include "ft2_mix.h" // MIXER_FRAC_BITS
 
+#define CUBIC4P_SPLINE_WIDTH 4
+#define CUBIC4P_SPLINE_WIDTH_BITS 2 /* log2(CUBIC4P_SPLINE_WIDTH */
 #define CUBIC4P_SPLINE_PHASES 8192
 #define CUBIC4P_SPLINE_PHASES_BITS 13 // log2(CUBIC4P_SPLINE_PHASES)
-#define CUBIC4P_SPLINE_FSHIFT (MIXER_FRAC_BITS-(CUBIC4P_SPLINE_PHASES_BITS+2))
-#define CUBIC4P_SPLINE_FMASK ((4*CUBIC4P_SPLINE_PHASES)-4)
+#define CUBIC4P_SPLINE_FRACSHIFT (MIXER_FRAC_BITS-(CUBIC4P_SPLINE_PHASES_BITS+CUBIC4P_SPLINE_WIDTH_BITS))
+#define CUBIC4P_SPLINE_FRACMASK ((CUBIC4P_SPLINE_WIDTH*CUBIC4P_SPLINE_PHASES)-CUBIC4P_SPLINE_WIDTH)
 
+#define CUBIC6P_SPLINE_WIDTH 6
 #define CUBIC6P_SPLINE_PHASES 8192
 #define CUBIC6P_SPLINE_PHASES_BITS 13 // log2(CUBIC6P_SPLINE_PHASES)
-#define CUBIC6P_SPLINE_FSHIFT (MIXER_FRAC_BITS-CUBIC6P_SPLINE_PHASES_BITS)
+#define CUBIC6P_SPLINE_FRACSHIFT (MIXER_FRAC_BITS-CUBIC6P_SPLINE_PHASES_BITS)
 
 extern float *f4PointCubicSplineLUT, *f6PointCubicSplineLUT;
 
-bool calcCubicSplineTables(void);
+bool setupCubicSplineTables(void);
 void freeCubicSplineTables(void);
--- a/src/mixer/ft2_mix_macros.h
+++ b/src/mixer/ft2_mix_macros.h
@@ -133,7 +133,7 @@
 
 #define CUBIC4P_SPLINE_INTERPOLATION(s, f, scale) \
 { \
-	const float *t = f4PointCubicSplineLUT + (((uint32_t)(f) >> CUBIC4P_SPLINE_FSHIFT) & CUBIC4P_SPLINE_FMASK); \
+	const float *t = f4PointCubicSplineLUT + (((uint32_t)(f) >> CUBIC4P_SPLINE_FRACSHIFT) & CUBIC4P_SPLINE_FRACMASK); \
 	fSample = ((s[-1] * t[0]) + \
 	           ( s[0] * t[1]) + \
 	           ( s[1] * t[2]) + \
@@ -142,7 +142,7 @@
 
 #define CUBIC6P_SPLINE_INTERPOLATION(s, f, scale) \
 { \
-	const float *t = f6PointCubicSplineLUT + (((uint32_t)(f) >> CUBIC6P_SPLINE_FSHIFT) * 6); \
+	const float *t = f6PointCubicSplineLUT + (((uint32_t)(f) >> CUBIC6P_SPLINE_FRACSHIFT) * CUBIC6P_SPLINE_WIDTH); \
 	fSample = ((s[-2] * t[0]) + \
 	           (s[-1] * t[1]) + \
 	           ( s[0] * t[2]) + \
@@ -215,7 +215,7 @@
 
 #define WINDOWED_SINC8_INTERPOLATION(s, f, scale) \
 { \
-	const float *t = v->fSincLUT + (((uint32_t)(f) >> SINC8_FSHIFT) & SINC8_FMASK); \
+	const float *t = v->fSincLUT + (((uint32_t)(f) >> SINC1_FRACSHIFT) & SINC1_FRACMASK); \
 	fSample = ((s[-3] * t[0]) + \
 	           (s[-2] * t[1]) + \
 	           (s[-1] * t[2]) + \
@@ -228,7 +228,7 @@
 
 #define WINDOWED_SINC16_INTERPOLATION(s, f, scale) \
 { \
-	const float *t = v->fSincLUT + (((uint32_t)(f) >> SINC16_FSHIFT) & SINC16_FMASK); \
+	const float *t = v->fSincLUT + (((uint32_t)(f) >> SINC2_FRACSHIFT) & SINC2_FRACMASK); \
 	fSample = (( s[-7] * t[0]) + \
 	           ( s[-6] * t[1]) + \
 	           ( s[-5] * t[2]) + \
--- a/src/mixer/ft2_windowed_sinc.c
+++ b/src/mixer/ft2_windowed_sinc.c
@@ -1,8 +1,5 @@
 /*
-** Windowed-sinc (Kaiser window) w/ low-pass interpolation LUT generator
-**
-** This was originally based on OpenMPT's source code,
-** but it has been heavily modified.
+** Windowed-sinc LUT generator
 */
 
 #include <stdint.h>
@@ -9,22 +6,20 @@
 #include <stdbool.h>
 #include <stdlib.h>
 #include <math.h>
-#include "ft2_windowed_sinc.h" // SINCx_TAPS, SINCx_PHASES
+#include "ft2_windowed_sinc.h" // SINCx_WIDTH, SINCx_PHASES
 #include "../ft2_header.h" // PI
 #include "../ft2_video.h" // showErrorMsgBox()
 
 // globalized
-float *fKaiserSinc_8 = NULL, *fDownSample1_8 = NULL, *fDownSample2_8 = NULL;
-float *fKaiserSinc_16 = NULL, *fDownSample1_16 = NULL, *fDownSample2_16 = NULL;
-uint64_t sincDownsample1Ratio, sincDownsample2Ratio;
+float *fSinc8_1 = NULL, *fSinc8_2 = NULL, *fSinc8_3 = NULL;
+float *fSinc16_1 = NULL, *fSinc16_2 = NULL, *fSinc16_3 = NULL;
+float *fSinc_1 = NULL, *fSinc_2 = NULL, *fSinc_3 = NULL;
+uint64_t sincRatio1, sincRatio2;
 
-// set based on selected sinc interpolator (8 point or 16 point)
-float *fKaiserSinc = NULL, *fDownSample1 = NULL, *fDownSample2 = NULL;
-
 // zeroth-order modified Bessel function of the first kind (series approximation)
-static double besselI0(double z)
+static inline double besselI0(double z)
 {
-#define EPSILON (1E-15)
+#define EPSILON (1E-15) /* lower than this gives no accuracy benefits (verified), just slower compute time */
 
 	double s = 1.0, ds = 1.0, d = 2.0;
 	const double zz = z * z;
@@ -40,109 +35,83 @@
 	return s;
 }
 
-static void generateSincLUT(float *fOutput, uint32_t filterWidth, uint32_t numPhases, const double beta, const double lpCutoff)
+static inline double sinc(double x, const double cutoff)
 {
-	const double I0Beta = besselI0(beta);
-	const double kPi = PI * lpCutoff;
-	const double iMul = 1.0 / numPhases;
-	const double xMul = 1.0 / ((filterWidth / 2) * (filterWidth / 2));
+	if (x == 0.0)
+	{
+		return cutoff;
+	}
+	else
+	{
+		x *= cutoff * PI;
+		return (sin(x) / x) * cutoff;
+	}
+}
 
-	const uint32_t length = filterWidth * numPhases;
-	const uint32_t tapBits = (uint32_t)log2(filterWidth);
-	const uint32_t phasesBits = (uint32_t)log2(numPhases);
-	const uint32_t tapsMinus1 = filterWidth - 1;
-	const int32_t midPoint = (filterWidth / 2) * numPhases;
+static void generateWindowedSinc(float *fOutput, const int32_t filterWidth, const int32_t filterPhases, const double beta, const double cutoff)
+{
+	const int32_t tapBits = (int32_t)log2(filterWidth);
+	const int32_t tapMask = filterWidth - 1;
+	const int32_t tapCenter = (filterWidth / 2) - 1;
+	const double besselI0Beta = 1.0 / besselI0(beta);
+	const double phaseMul = 1.0 / filterPhases;
+	const double xMul = 1.0 / (filterWidth / 2);
 
-	for (uint32_t i = 0; i < length; i++)
+	for (int32_t i = 0; i < filterWidth * filterPhases; i++)
 	{
-		const int32_t ix = ((tapsMinus1 - (i & tapsMinus1)) << phasesBits) + (i >> tapBits);
+		const double x = ((i & tapMask) - tapCenter) - ((i >> tapBits) * phaseMul);
 
-		double dSinc = 1.0;
-		if (ix != midPoint)
-		{
-			const double x = (ix - midPoint) * iMul;
-			const double xPi = x * kPi;
+		// Kaiser-Bessel window
+		const double n = x * xMul;
+		const double window = besselI0(beta * sqrt(1.0 - n * n)) * besselI0Beta;
 
-			// Kaiser window
-			dSinc = (sin(xPi) * besselI0(beta * sqrt(1.0 - (x * x * xMul)))) / (I0Beta * xPi);
-		}
-
-		fOutput[i] = (float)(dSinc * lpCutoff);
+		fOutput[i] = (float)(sinc(x, cutoff) * window);
 	}
 }
 
-static double decibelsToKaiserBeta(double dB)
+bool setupWindowedSincTables(void)
 {
-	if (dB < 21.0)
-		return 0.0;
-	else if (dB <= 50.0)
-		return 0.5842 * pow(dB - 21.0, 0.4) + 0.07886 * (dB - 21.0);
-	else
-		return 0.1102 * (dB - 8.7);
-}
+	fSinc8_1  = (float *)malloc(SINC1_WIDTH*SINC1_PHASES * sizeof (float));
+	fSinc8_2  = (float *)malloc(SINC1_WIDTH*SINC1_PHASES * sizeof (float));
+	fSinc8_3  = (float *)malloc(SINC1_WIDTH*SINC1_PHASES * sizeof (float));
+	fSinc16_1 = (float *)malloc(SINC2_WIDTH*SINC2_PHASES * sizeof (float));
+	fSinc16_2 = (float *)malloc(SINC2_WIDTH*SINC2_PHASES * sizeof (float));
+	fSinc16_3 = (float *)malloc(SINC2_WIDTH*SINC2_PHASES * sizeof (float));
 
-static double rippleToDecibels(double ripple)
-{
-	return 20.0 * log10(ripple);
-}
-
-bool calcWindowedSincTables(void)
-{
-	fKaiserSinc_8   = (float *)malloc(SINC1_TAPS*SINC1_PHASES * sizeof (float));
-	fDownSample1_8  = (float *)malloc(SINC1_TAPS*SINC1_PHASES * sizeof (float));
-	fDownSample2_8  = (float *)malloc(SINC1_TAPS*SINC1_PHASES * sizeof (float));
-	fKaiserSinc_16  = (float *)malloc(SINC2_TAPS*SINC2_PHASES * sizeof (float));
-	fDownSample1_16 = (float *)malloc(SINC2_TAPS*SINC2_PHASES * sizeof (float));
-	fDownSample2_16 = (float *)malloc(SINC2_TAPS*SINC2_PHASES * sizeof (float));
-
-	if (fKaiserSinc_8  == NULL || fDownSample1_8  == NULL || fDownSample2_8  == NULL ||
-		fKaiserSinc_16 == NULL || fDownSample1_16 == NULL || fDownSample2_16 == NULL)
+	if (fSinc8_1  == NULL || fSinc8_2  == NULL || fSinc8_3  == NULL ||
+		fSinc16_1 == NULL || fSinc16_2 == NULL || fSinc16_3 == NULL)
 	{
 		showErrorMsgBox("Not enough memory!");
 		return false;
 	}
 
-	// resampling ratios for picking suitable downsample LUT
-	const double ratio1 = 1.1875; // fKaiserSinc if <=
-	const double ratio2 = 1.5; // fDownSample1 if <=, fDownSample2 if >
+	// LUT-select resampling ratios
+	const double ratio1 = 1.1875; // fSinc_1 if <=
+	const double ratio2 = 1.5; // fSinc_2 if <=, fSinc_3 if >
 
-	sincDownsample1Ratio = (uint64_t)(ratio1 * MIXER_FRAC_SCALE);
-	sincDownsample2Ratio = (uint64_t)(ratio2 * MIXER_FRAC_SCALE);
+	// calculate mixer delta limits for LUT-selector
+	sincRatio1 = (uint64_t)(ratio1 * MIXER_FRAC_SCALE);
+	sincRatio2 = (uint64_t)(ratio2 * MIXER_FRAC_SCALE);
 
-	/* Max ripple (to be converted into Kaiser beta parameter)
-	**
-	** NOTE:
-	**  These may not be the correct values. Proper calculation
-	**  is needed, but is beyond my knowledge.
-	*/
-	const double maxRipple1 = 1 << 16;
-	const double maxRipple2 = 1 << 14;
-	const double maxRipple3 = 1 << 12;
+	// Kaiser-Bessel (window) beta (could maybe use some further tweaking)
+	const double b1 = 9.6;
+	const double b2 = 8.5;
+	const double b3 = 7.0;
 
-	// convert max ripple into sidelode attenuation (dB)
-	double db1 = rippleToDecibels(maxRipple1);
-	double db2 = rippleToDecibels(maxRipple2);
-	double db3 = rippleToDecibels(maxRipple3);
-
-	// convert sidelobe attenuation (dB) into Kaiser beta
-	const double b1 = decibelsToKaiserBeta(db1);
-	const double b2 = decibelsToKaiserBeta(db2);
-	const double b3 = decibelsToKaiserBeta(db3);
-
-	// low-pass cutoffs (could maybe use some further tweaking)
+	// sinc low-pass cutoff (could maybe use some further tweaking)
 	const double c1 = 1.000;
 	const double c2 = 0.500;
 	const double c3 = 0.425;
 
 	// 8 point
-	generateSincLUT(fKaiserSinc_8,   SINC1_TAPS, SINC1_PHASES, b1, c1);
-	generateSincLUT(fDownSample1_8,  SINC1_TAPS, SINC1_PHASES, b2, c2);
-	generateSincLUT(fDownSample2_8,  SINC1_TAPS, SINC1_PHASES, b3, c3);
+	generateWindowedSinc(fSinc8_1,  SINC1_WIDTH, SINC1_PHASES, b1, c1);
+	generateWindowedSinc(fSinc8_2,  SINC1_WIDTH, SINC1_PHASES, b2, c2);
+	generateWindowedSinc(fSinc8_3,  SINC1_WIDTH, SINC1_PHASES, b3, c3);
 
 	// 16 point
-	generateSincLUT(fKaiserSinc_16,  SINC2_TAPS, SINC2_PHASES, b1, c1);
-	generateSincLUT(fDownSample1_16, SINC2_TAPS, SINC2_PHASES, b2, c2);
-	generateSincLUT(fDownSample2_16, SINC2_TAPS, SINC2_PHASES, b3, c3);
+	generateWindowedSinc(fSinc16_1, SINC2_WIDTH, SINC2_PHASES, b1, c1);
+	generateWindowedSinc(fSinc16_2, SINC2_WIDTH, SINC2_PHASES, b2, c2);
+	generateWindowedSinc(fSinc16_3, SINC2_WIDTH, SINC2_PHASES, b3, c3);
 
 	return true;
 }
@@ -149,39 +118,39 @@
 
 void freeWindowedSincTables(void)
 {
-	if (fKaiserSinc_8 != NULL)
+	if (fSinc8_1 != NULL)
 	{
-		free(fKaiserSinc_8);
-		fKaiserSinc_8 = NULL;
+		free(fSinc8_1);
+		fSinc8_1 = NULL;
 	}
 
-	if (fDownSample1_8 != NULL)
+	if (fSinc8_2 != NULL)
 	{
-		free(fDownSample1_8);
-		fDownSample1_8 = NULL;
+		free(fSinc8_2);
+		fSinc8_2 = NULL;
 	}
 
-	if (fDownSample2_8 != NULL)
+	if (fSinc8_3 != NULL)
 	{
-		free(fDownSample2_8);
-		fDownSample2_8 = NULL;
+		free(fSinc8_3);
+		fSinc8_3 = NULL;
 	}
 
-	if (fKaiserSinc_16 != NULL)
+	if (fSinc16_1 != NULL)
 	{
-		free(fKaiserSinc_16);
-		fKaiserSinc_16 = NULL;
+		free(fSinc16_1);
+		fSinc16_1 = NULL;
 	}
 
-	if (fDownSample1_16 != NULL)
+	if (fSinc16_2 != NULL)
 	{
-		free(fDownSample1_16);
-		fDownSample1_16 = NULL;
+		free(fSinc16_2);
+		fSinc16_2 = NULL;
 	}
 
-	if (fDownSample2_16 != NULL)
+	if (fSinc16_3 != NULL)
 	{
-		free(fDownSample2_16);
-		fDownSample2_16 = NULL;
+		free(fSinc16_3);
+		fSinc16_3 = NULL;
 	}
 }
--- a/src/mixer/ft2_windowed_sinc.h
+++ b/src/mixer/ft2_windowed_sinc.h
@@ -4,25 +4,24 @@
 #include <stdbool.h>
 #include "ft2_mix.h" // MIXER_FRAC_BITS
 
-#define SINC1_TAPS 8
-#define SINC8_WIDTH_BITS 3 // log2(SINC1_TAPS)
+#define SINC1_WIDTH 8
+#define SINC1_WIDTH_BITS 3 // log2(SINC1_WIDTH)
 #define SINC1_PHASES 8192
 #define SINC1_PHASES_BITS 13 // log2(SINC1_PHASES)
-#define SINC8_FSHIFT (MIXER_FRAC_BITS-(SINC1_PHASES_BITS+SINC8_WIDTH_BITS))
-#define SINC8_FMASK ((SINC1_TAPS*SINC1_PHASES)-SINC1_TAPS)
+#define SINC1_FRACSHIFT (MIXER_FRAC_BITS-(SINC1_PHASES_BITS+SINC1_WIDTH_BITS))
+#define SINC1_FRACMASK ((SINC1_WIDTH*SINC1_PHASES)-SINC1_WIDTH)
 
-#define SINC2_TAPS 16
-#define SINC16_WIDTH_BITS 4 // log2(SINC2_TAPS)
+#define SINC2_WIDTH 16
+#define SINC2_WIDTH_BITS 4 // log2(SINC2_WIDTH)
 #define SINC2_PHASES 8192
 #define SINC2_PHASES_BITS 13 // log2(SINC2_PHASES)
-#define SINC16_FSHIFT (MIXER_FRAC_BITS-(SINC2_PHASES_BITS+SINC16_WIDTH_BITS))
-#define SINC16_FMASK ((SINC2_TAPS*SINC2_PHASES)-SINC2_TAPS)
+#define SINC2_FRACSHIFT (MIXER_FRAC_BITS-(SINC2_PHASES_BITS+SINC2_WIDTH_BITS))
+#define SINC2_FRACMASK ((SINC2_WIDTH*SINC2_PHASES)-SINC2_WIDTH)
 
-extern float *fKaiserSinc_8, *fDownSample1_8, *fDownSample2_8;
-extern float *fKaiserSinc_16, *fDownSample1_16, *fDownSample2_16;
+extern float *fSinc8_1, *fSinc8_2, *fSinc8_3;
+extern float *fSinc16_1, *fSinc16_2, *fSinc16_3;
+extern float *fSinc_1, *fSinc_2, *fSinc_3;
+extern uint64_t sincRatio1, sincRatio2;
 
-extern float *fKaiserSinc, *fDownSample1, *fDownSample2;
-extern uint64_t sincDownsample1Ratio, sincDownsample2Ratio;
-
-bool calcWindowedSincTables(void);
+bool setupWindowedSincTables(void);
 void freeWindowedSincTables(void);
--