Open source high-quality pro audio sample rate converter library released from Voxengo

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

Tale wrote:Just to make sure I am correctly understanding how this library is licensed: If I use this in a (closed-source) project, say Combo Model F, you are happy as long as I credit you (as specified in other/License.txt) in the PDF documentation, right?
Yes, that's right. You do not have to release your source, it's not GPL license.
Image

Post

Aleksey Vaneev wrote:Yes, that's right. You do not have to release your source, it's not GPL license.
Cool, thanks! :cool: Of course I would share any improvements on r8brain itself (not very likely, because I have yet to figure out how the heck it works... :oops: ).

Post

I have fetched the latest changes (thanks for the fixes!), and I have now successfully tested r8brain on:
  • Windows SDK v7.0 (MSVC 2008 compiler) targetting x86
  • Windows SDK v7.1 (MSVC 2010 compiler) targetting x64
  • Xcode 3.2.6 targetting i386 and x86-64 (and PPC, but I can't easily test if it actually works; it compiles just fine)

Post

Thanks.
Image

Post

I have found a signed/unsigned bug (at least on my compiler) in getBitOccupancy(). If I call getBitOccupancy(2147483648) it returns 24, while it should return 32. Fix:

Code: Select all

diff --git a/r8bbase.h b/r8bbase.h
index 1130e01..0009825 100644
--- a/r8bbase.h
+++ b/r8bbase.h
@@ -764,7 +764,7 @@ inline int getBitOccupancy( const int v )
 
 	if( tt != 0 )
 	{
-		return(( t = v >> 24 ) ? 24 + OccupancyTable[ t ] :
+		return(( t = (unsigned int) v >> 24 ) ? 24 + OccupancyTable[ t ] :
 			16 + OccupancyTable[ tt & 0xFF ]);
 	}
 	else
BTW, you could replace the OccupancyTable[] with a inline function, thus saving about 1 kB static memory. There is only a very, very small performance penalty, and I think getBitOccupancy() isn't a critical function anyway, so I'd say saving 1 kB is worth it. Patch:

Code: Select all

diff --git a/r8bbase.h b/r8bbase.h
index 1130e01..73c4b96 100644
--- a/r8bbase.h
+++ b/r8bbase.h
@@ -737,40 +737,31 @@ private:
  * specified value. Function treats the input value as unsigned.
  */
 
+inline int _getBitOccupancy( const int v )
+{
+	if( v & 0x80 ) return 8;
+	if( v & 0x40 ) return 7;
+	if( v & 0x20 ) return 6;
+	if( v & 0x10 ) return 5;
+	if( v & 0x08 ) return 4;
+	if( v & 0x04 ) return 3;
+	if( v & 0x02 ) return 2;
+	return 1;
+}
 inline int getBitOccupancy( const int v )
 {
-	static const int OccupancyTable[] =
-	{
-		1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
-		5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-		8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-		8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-		8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-		8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-		8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-		8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-		8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-		8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
-	};
-
 	int t, tt;
 	tt = v >> 16;
 
 	if( tt != 0 )
 	{
-		return(( t = v >> 24 ) ? 24 + OccupancyTable[ t ] :
-			16 + OccupancyTable[ tt & 0xFF ]);
+		return(( t = (unsigned int) v >> 24 ) ? 24 + _getBitOccupancy( t ) :
+			16 + _getBitOccupancy( tt & 0xFF ));
 	}
 	else
 	{
-		return(( t = v >> 8 ) ? 8 + OccupancyTable[ t ] :
-			OccupancyTable[ v ]);
+		return(( t = v >> 8 ) ? 8 + _getBitOccupancy( t ) :
+			_getBitOccupancy( v ));
 	}
 }
 

Post

Thanks for the getBitOccupancy() fix, but I won't replace the table, the set of "if"s is less optimal. However, "static const int" can be changed to "static const char", that's the thing I've overlooked.

The 2147483648 value does not fit into 32-bit "int" range, so this function isn't applicable. While the -2147483648 works OK. The fix is not needed.
Last edited by Aleksey Vaneev on Sat Aug 24, 2013 11:09 am, edited 1 time in total.
Image

Post

Aleksey Vaneev wrote:Thanks for the getBitOccupancy() fix, but I won't replace the table, the set of "if"s is less optimal. However, "static const int" can be changed to "static const char", that's the thing I've overlooked.
Fair enough.

Post

I have been playing with r8brain-free-src some more, comparing it with my current linear interpolation resampling method, and the resampler in Cockos WDL. On average r8brain (with ReqTransBand=3 and ReqAtten=70) is ~19x slower than linear interpolation, and WDL's resampler (using defaults, which I think corresponds with REAPER's "Good" 64pt sinc mode) is ~14x slower. However, for the special case where I upsample 44.1 to 88.2 kHz (where r8brain uses its "power of 2" upsampling), r8brain is twice as fast as WDL's resampler. Note that I am not using IPP.

Also note that I am kinda comparing apples and oranges, as I haven't looked at the quality (I am resampling IRs, where quality seems less of an issue). Obviously both resamplers are better than my current linear interpolation method, but I guess r8brain (even with ReqAtten=70) is probably also better than WDL's resampler using defaults.
Aleksey Vaneev wrote:Thanks for the getBitOccupancy() fix
Reminder: I have just updated to the latest revision (r34), but the getBitOccupancy() bug is still there. BTW, the bug also manifests itself when using GCC.

Post

As I've replied earlier, 2147483648 does NOT fit into 32-bit "int" range. Your test was flawed.

I'm currently working on a better windowing function, and I think the number of taps can be reduced further down to 34 or 32 samples, that way it will be 10-15% faster.

With r8brain-free-src we are talking about constantly *excellent* quality, there is simply no much room for improvement left.

For a fair comparison you may also decrease ReqTransBand and increase ReqAtten if necessary - this won't make r8brain-free-src much slower.
Last edited by Aleksey Vaneev on Sun Aug 25, 2013 1:46 pm, edited 1 time in total.
Image

Post

Aleksey Vaneev wrote:there is simply no much room for improvement left.
Continuously variable rate? :D

Post

AdmiralQuality wrote:
Aleksey Vaneev wrote:there is simply no much room for improvement left.
Continuously variable rate? :D
This was already done in the CDSPFracInterpolator class, except that low-pass filtering is non-dynamic. If you have a dynamic low-pass filter (with 2X oversampling) implementation, you can use that class for variable rate interpolation.
Image

Post

Aleksey Vaneev wrote:
AdmiralQuality wrote:
Aleksey Vaneev wrote:there is simply no much room for improvement left.
Continuously variable rate? :D
This was already done in the CDSPFracInterpolator class, except that low-pass filtering is non-dynamic. If you have a dynamic low-pass filter (with 2X oversampling) implementation, you can use that class for variable rate interpolation.
Oh? Sorry, I saw your earlier post saying this wasn't really suitable for continuous rate. Will check it out now if it is. Thanks!

Post

AdmiralQuality wrote:Oh? Sorry, I saw your earlier post saying this wasn't really suitable for continuous rate. Will check it out now if it is. Thanks!
Well, you can continously change the rate in the current implementation, but it isn't smooth as, for example, usual chorus implementations that use an oscillator for stepping.

So, I will probably take CDSPFracInterpolator to the next step in the future: a fully continuous rate change, driven by an oscillator. Plus the input data can be supplied as a list of data blocks, with forward or backward reading (should be great for ping-pong and usual looping). The output length can be also limited. This way it will be really easy to put this interpolator into a soft-synth.
Last edited by Aleksey Vaneev on Sun Aug 25, 2013 2:01 pm, edited 1 time in total.
Image

Post

Aleksey Vaneev wrote:
AdmiralQuality wrote:Oh? Sorry, I saw your earlier post saying this wasn't really suitable for continuous rate. Will check it out now if it is. Thanks!
Well, you can continously change the rate in the current implementation, but it isn't smooth as, for example, usual chorus implementations that use an oscillator for stepping.
Oh. That would be what I'd want it for. Delay/chorus/flanger type stuff.

So, I will probably take CDSPFracInterpolator to the next step in the future: a fully continuous rate change, driven by an oscillator. Plus the input data can be supplied as a list of data blocks, with forward or backward reading. The output length can be also limited. This way it will be really easy to put this interpolator into a soft-synths.
And effects! :tu:

Post

Aleksey Vaneev wrote:As I've replied earlier, 2147483648 does NOT fit into 32-bit "int" range. Your test was flawed.
Sorry, I seem to have missed your earlier reply. My confusion came from the "function treats the input value as unsigned", but you are absolutely right. Thanks for explaining (twice). :)

Post Reply

Return to “DSP and Plugin Development”