shithub: libsamplerate

Download patch

ref: 67a8c942dd86c9febb9168dde524977b3f3a6421
parent: a3cfc1510d8caa091bcfec5f9ab8892ae71638c3
author: Alexander Grund <alexander.grund@tu-dresden.de>
date: Tue Aug 27 09:09:01 EDT 2019

Move buffer-underflow handling out of hot loop

The event `data_index < 0` can be handled once by a simple arithmetic
operation instead of beeing checked once per loop in the computationally
most expensive loop.

--- a/src/src_sinc.c
+++ b/src/src_sinc.c
@@ -94,6 +94,11 @@
 {	return fp_fraction_part (x) * INV_FP_ONE ;
 } /* fp_to_double */
 
+static inline int
+int_div_ceil (int divident, int divisor) /* == (int) ceil ((float) divident / divisor) */
+{	assert (divident >= 0 && divisor > 0) ; /* For positive numbers only */
+	return (divident + (divisor - 1)) / divisor ;
+}
 
 /*----------------------------------------------------------------------------------------
 */
@@ -295,22 +300,26 @@
 	filter_index = filter_index + coeff_count * increment ;
 	data_index = filter->b_current - coeff_count ;
 
+	if (data_index < 0) /* Avoid underflow access to filter->buffer. */
+	{	int steps = -data_index ;
+		/* If the assert triggers we would have to take care not to underflow/overflow */
+		assert (steps <= int_div_ceil (filter_index, increment)) ;
+		filter_index -= increment * steps ;
+		data_index += steps ;
+	}
 	left = 0.0 ;
-	do
-	{	if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
-		{	fraction = fp_to_double (filter_index) ;
-			indx = fp_to_int (filter_index) ;
-			assert (indx >= 0 && indx + 1 < filter->coeff_half_len + 2) ;
-			icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
-			assert (data_index >= 0 && data_index < filter->b_len) ;
-			assert (data_index < filter->b_end) ;
-			left += icoeff * filter->buffer [data_index] ;
-			}  ;
+	while (filter_index >= MAKE_INCREMENT_T (0))
+	{	fraction = fp_to_double (filter_index) ;
+		indx = fp_to_int (filter_index) ;
+		assert (indx >= 0 && indx + 1 < filter->coeff_half_len + 2) ;
+		icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
+		assert (data_index >= 0 && data_index < filter->b_len) ;
+		assert (data_index < filter->b_end) ;
+		left += icoeff * filter->buffer [data_index] ;
 
 		filter_index -= increment ;
 		data_index = data_index + 1 ;
-		}
-	while (filter_index >= MAKE_INCREMENT_T (0)) ;
+		} ;
 
 	/* Now apply the right half of the filter. */
 	filter_index = increment - start_filter_index ;
@@ -444,23 +453,27 @@
 	filter_index = filter_index + coeff_count * increment ;
 	data_index = filter->b_current - filter->channels * coeff_count ;
 
+	if (data_index < 0) /* Avoid underflow access to filter->buffer. */
+	{	int steps = int_div_ceil (-data_index, 2) ;
+		/* If the assert triggers we would have to take care not to underflow/overflow */
+		assert (steps <= int_div_ceil (filter_index, increment)) ;
+		filter_index -= increment * steps ;
+		data_index += steps * 2;
+	}
 	left [0] = left [1] = 0.0 ;
-	do
-	{	if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
-		{	fraction = fp_to_double (filter_index) ;
-			indx = fp_to_int (filter_index) ;
-			assert (indx >= 0 && indx + 1 < filter->coeff_half_len + 2) ;
-			icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
-			assert (data_index >= 0 && data_index + 1 < filter->b_len) ;
-			assert (data_index + 1 < filter->b_end) ;
-			for (int ch = 0; ch < 2; ch++)
-				left [ch] += icoeff * filter->buffer [data_index + ch] ;
-			} ;
+	while (filter_index >= MAKE_INCREMENT_T (0))
+	{	fraction = fp_to_double (filter_index) ;
+		indx = fp_to_int (filter_index) ;
+		assert (indx >= 0 && indx + 1 < filter->coeff_half_len + 2) ;
+		icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
+		assert (data_index >= 0 && data_index + 1 < filter->b_len) ;
+		assert (data_index + 1 < filter->b_end) ;
+		for (int ch = 0; ch < 2; ch++)
+			left [ch] += icoeff * filter->buffer [data_index + ch] ;
 
 		filter_index -= increment ;
 		data_index = data_index + 2 ;
-		}
-	while (filter_index >= MAKE_INCREMENT_T (0)) ;
+		} ;
 
 	/* Now apply the right half of the filter. */
 	filter_index = increment - start_filter_index ;
@@ -595,23 +608,27 @@
 	filter_index = filter_index + coeff_count * increment ;
 	data_index = filter->b_current - filter->channels * coeff_count ;
 
+	if (data_index < 0) /* Avoid underflow access to filter->buffer. */
+	{	int steps = int_div_ceil (-data_index, 4) ;
+		/* If the assert triggers we would have to take care not to underflow/overflow */
+		assert (steps <= int_div_ceil (filter_index, increment)) ;
+		filter_index -= increment * steps ;
+		data_index += steps * 4;
+	}
 	left [0] = left [1] = left [2] = left [3] = 0.0 ;
-	do
-	{	if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
-		{	fraction = fp_to_double (filter_index) ;
-			indx = fp_to_int (filter_index) ;
-			assert (indx >= 0 && indx + 1 < filter->coeff_half_len + 2) ;
-			icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
-			assert (data_index >= 0 && data_index + 3 < filter->b_len) ;
-			assert (data_index + 3 < filter->b_end) ;
-			for (int ch = 0; ch < 4; ch++)
-				left [ch] += icoeff * filter->buffer [data_index + ch] ;
-			} ;
+	while (filter_index >= MAKE_INCREMENT_T (0))
+	{	fraction = fp_to_double (filter_index) ;
+		indx = fp_to_int (filter_index) ;
+		assert (indx >= 0 && indx + 1 < filter->coeff_half_len + 2) ;
+		icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
+		assert (data_index >= 0 && data_index + 3 < filter->b_len) ;
+		assert (data_index + 3 < filter->b_end) ;
+		for (int ch = 0; ch < 4; ch++)
+			left [ch] += icoeff * filter->buffer [data_index + ch] ;
 
 		filter_index -= increment ;
 		data_index = data_index + 4 ;
-		}
-	while (filter_index >= MAKE_INCREMENT_T (0)) ;
+		} ;
 
 	/* Now apply the right half of the filter. */
 	filter_index = increment - start_filter_index ;
@@ -747,23 +764,27 @@
 	filter_index = filter_index + coeff_count * increment ;
 	data_index = filter->b_current - filter->channels * coeff_count ;
 
+	if (data_index < 0) /* Avoid underflow access to filter->buffer. */
+	{	int steps = int_div_ceil (-data_index, 6) ;
+		/* If the assert triggers we would have to take care not to underflow/overflow */
+		assert (steps <= int_div_ceil (filter_index, increment)) ;
+		filter_index -= increment * steps ;
+		data_index += steps * 6;
+	}
 	left [0] = left [1] = left [2] = left [3] = left [4] = left [5] = 0.0 ;
-	do
-	{	if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
-		{	fraction = fp_to_double (filter_index) ;
-			indx = fp_to_int (filter_index) ;
-			assert (indx >= 0 && indx + 1 < filter->coeff_half_len + 2) ;
-			icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
-			assert (data_index >= 0 && data_index + 5 < filter->b_len) ;
-			assert (data_index + 5 < filter->b_end) ;
-			for (int ch = 0; ch < 6; ch++)
-				left [ch] += icoeff * filter->buffer [data_index + ch] ;
-			} ;
+	while (filter_index >= MAKE_INCREMENT_T (0))
+	{	fraction = fp_to_double (filter_index) ;
+		indx = fp_to_int (filter_index) ;
+		assert (indx >= 0 && indx + 1 < filter->coeff_half_len + 2) ;
+		icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
+		assert (data_index >= 0 && data_index + 5 < filter->b_len) ;
+		assert (data_index + 5 < filter->b_end) ;
+		for (int ch = 0; ch < 6; ch++)
+			left [ch] += icoeff * filter->buffer [data_index + ch] ;
 
 		filter_index -= increment ;
 		data_index = data_index + 6 ;
-		}
-	while (filter_index >= MAKE_INCREMENT_T (0)) ;
+		} ;
 
 	/* Now apply the right half of the filter. */
 	filter_index = increment - start_filter_index ;
@@ -903,25 +924,30 @@
 	filter_index = filter_index + coeff_count * increment ;
 	data_index = filter->b_current - channels * coeff_count ;
 
+	if (data_index < 0) /* Avoid underflow access to filter->buffer. */
+	{	int steps = int_div_ceil (-data_index, channels) ;
+		/* If the assert triggers we would have to take care not to underflow/overflow */
+		assert (steps <= int_div_ceil (filter_index, increment)) ;
+		filter_index -= increment * steps ;
+		data_index += steps * channels ;
+	}
+
 	memset (left, 0, sizeof (left [0]) * channels) ;
 
-	do
+	while (filter_index >= MAKE_INCREMENT_T (0))
 	{	fraction = fp_to_double (filter_index) ;
 		indx = fp_to_int (filter_index) ;
 		assert (indx >= 0 && indx + 1 < filter->coeff_half_len + 2) ;
 		icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
 
-		if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
-		{	assert (data_index >= 0 && data_index + channels - 1 < filter->b_len) ;
-			assert (data_index + channels - 1 < filter->b_end) ;
-			for (int ch = 0; ch < channels; ch++)
-				left [ch] += icoeff * filter->buffer [data_index + ch] ;
-			} ;
+		assert (data_index >= 0 && data_index + channels - 1 < filter->b_len) ;
+		assert (data_index + channels - 1 < filter->b_end) ;
+		for (int ch = 0; ch < channels; ch++)
+			left [ch] += icoeff * filter->buffer [data_index + ch] ;
 
 		filter_index -= increment ;
 		data_index = data_index + channels ;
-		}
-	while (filter_index >= MAKE_INCREMENT_T (0)) ;
+		} ;
 
 	/* Now apply the right half of the filter. */
 	filter_index = increment - start_filter_index ;