shithub: cstory

Download patch

ref: 67ee8b982972c8d5a63416a5edbdbbc367f2d162
parent: 9f002b618081265a0051110502710d414776e4c2
author: Clownacy <Clownacy@users.noreply.github.com>
date: Thu Sep 3 10:28:04 EDT 2020

Optimise the Lanczos resampler some more

--- a/src/Backends/Audio/SoftwareMixer.cpp
+++ b/src/Backends/Audio/SoftwareMixer.cpp
@@ -10,6 +10,8 @@
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 #define CLAMP(x, y, z) MIN(MAX((x), (y)), (z))
 
+#define LANCZOS_KERNEL_RADIUS 2
+
 struct Mixer_Sound
 {
 	signed char *samples;
@@ -51,10 +53,11 @@
 	if (sound == NULL)
 		return NULL;
 
+	// Both interpolators will read outside the array's bounds, so allocate some extra room
 #ifdef LANCZOS_RESAMPLER
-	sound->samples = (signed char*)malloc(length);
+	sound->samples = (signed char*)malloc(LANCZOS_KERNEL_RADIUS - 1 + length + LANCZOS_KERNEL_RADIUS);
 #else
-	sound->samples = (signed char*)malloc(length + 1);	// +1 for the linear-interpolator
+	sound->samples = (signed char*)malloc(length + 1);
 #endif
 
 	if (sound->samples == NULL)
@@ -63,6 +66,14 @@
 		return NULL;
 	}
 
+#ifdef LANCZOS_RESAMPLER
+	// Blank samples outside the array bounds (we'll deal with the other half later)
+	for (size_t i = 0; i < LANCZOS_KERNEL_RADIUS - 1; ++i)
+		sound->samples[i] = 0;
+
+	sound->samples += LANCZOS_KERNEL_RADIUS - 1;
+#endif
+
 	for (size_t i = 0; i < length; ++i)
 		sound->samples[i] = samples[i] - 0x80;	// Convert from unsigned 8-bit PCM to signed
 
@@ -88,6 +99,9 @@
 		if (*sound_pointer == sound)
 		{
 			*sound_pointer = sound->next;
+		#ifdef LANCZOS_RESAMPLER
+			sound->samples -= LANCZOS_KERNEL_RADIUS - 1;
+		#endif
 			free(sound->samples);
 			free(sound);
 			break;
@@ -100,8 +114,17 @@
 	sound->playing = true;
 	sound->looping = looping;
 
-#ifndef LANCZOS_RESAMPLER
-	sound->samples[sound->frames] = looping ? sound->samples[0] : 0;	// For the linear interpolator
+	// Fill the out-of-bounds part of the buffer with
+	// either blank samples or repeated samples
+#ifdef LANCZOS_RESAMPLER
+	if (looping)
+		for (size_t i = 0; i < LANCZOS_KERNEL_RADIUS; ++i)
+			sound->samples[sound->frames + i] = sound->samples[i];
+	else
+		for (size_t i = 0; i < LANCZOS_KERNEL_RADIUS; ++i)
+			sound->samples[sound->frames + i] = 0;
+#else
+	sound->samples[sound->frames] = looping ? sound->samples[0] : 0;
 #endif
 }
 
@@ -151,13 +174,11 @@
 			{
 			#ifdef LANCZOS_RESAMPLER
 				// Perform Lanczos resampling
-				const int kernel_radius = 2;
-
 				float accumulator = 0;
 
-				for (int i = -MIN(kernel_radius - 1, sound->position); i <= kernel_radius; ++i)
+				for (int i = -LANCZOS_KERNEL_RADIUS + 1; i <= LANCZOS_KERNEL_RADIUS; ++i)
 				{
-					const signed char input_sample = sound->samples[(sound->position + i) % sound->frames];
+					const signed char input_sample = sound->samples[sound->position + i];
 
 					const float kernel_input = ((float)sound->position_subsample / 0x10000) - i;
 
@@ -168,7 +189,7 @@
 					else
 					{
 						const float nx = 3.14159265358979323846f * kernel_input;
-						const float nxa = nx / kernel_radius;
+						const float nxa = nx / LANCZOS_KERNEL_RADIUS;
 
 						accumulator += input_sample * (sin(nx) * sin(nxa) / (nx * nxa));
 					}