Open source high-quality pro audio sample rate converter library released from Voxengo
- KVRian
- 872 posts since 6 Aug, 2005 from England
I’m looking at this with great interest, but I’m wondering about the decision to not go with allowing floats as an input? Most people’s internal precision is probably still in floats. Not allowing them just seems like a needless enforcement for such a useful tool.
It all looks fantastic though. Well done, and thank-you.
Dave H.
It all looks fantastic though. Well done, and thank-you.
Dave H.
Dave Hoskins. http://www.quikquak.com
- KVRAF
- Topic Starter
- 4021 posts since 7 Sep, 2002
No reason to use floats at all for such unintensive memory process, doubles are actually a little bit more efficient, probably because loading 64-bit values has less latency than loading 32-bit values, from math CPU footprint 32-bit and 64-bit floats seem to be equivalent, 1 tick per op or so.quikquak wrote: ↑Mon Oct 22, 2018 8:20 am I’m looking at this with great interest, but I’m wondering about the decision to not go with allowing floats as an input? Most people’s internal precision is probably still in floats. Not allowing them just seems like a needless enforcement for such a useful tool.
It all looks fantastic though. Well done, and thank-you.
Dave H.
- KVRian
- 872 posts since 6 Aug, 2005 from England
For a tool, it’s quite important from a usability standpoint, I wanted to use SSE in my prior processing, and I’m still not confident in everybody having SSE2 processors. Are other developers just doing a float to double conversion before calling this I wonder? - Seems a bit of a waste. Or perhaps I should just go with doubles in my entire plugin...
Dave Hoskins. http://www.quikquak.com
- KVRAF
- Topic Starter
- 4021 posts since 7 Sep, 2002
Going from float to double and back, is inexpensive operation. I think overall it may be as efficient as performing sample rate conversion in floats. SSE2 support is now a bare minimum.quikquak wrote: ↑Mon Oct 22, 2018 12:08 pm For a tool, it’s quite important from a usability standpoint, I wanted to use SSE in my prior processing, and I’m still not confident in everybody having SSE2 processors. Are other developers just doing a float to double conversion before calling this I wonder? - Seems a bit of a waste. Or perhaps I should just go with doubles in my entire plugin...
- KVRian
- 872 posts since 6 Aug, 2005 from England
- KVRian
- 872 posts since 6 Aug, 2005 from England
I have a slight issue with real-time usage, I hope you can help after all this time please:
In my pre-play function I setup up two (it's a stereo signal)
'internalRate' is the plug-ins internal processing sample rate, which is 88200.0
'sameRate' is the host sample rate.
'internalSize' is the hosts max. block size * conversion ratio, which in my case is 1024 * 88200./44100.0Hz
Everything works perfectly until I set the host sample rate to 48000Hz which creates a fractional conversion ratio.
I get one sample of noise, I think it's from rounding errors it generates 1 less samples than I need for the current buffer fill, which could be any size as you know.
What is the best strategy in coping with these fractional sample rate changes when using a real-time buffer? Do I make 1 extra sample each frame and somehow wind back my internal processing by one sample the next time around?
I don't clear it every frame I just do what the example.cpp shows. Except of course I have an inflexible destination size.
Thanks.
Dave H.
In my pre-play function I setup up two (it's a stereo signal)
Code: Select all
Resamps[c] = new r8b::CDSPResampler24(internalRate,sampleRate, internalSize);
'sameRate' is the host sample rate.
'internalSize' is the hosts max. block size * conversion ratio, which in my case is 1024 * 88200./44100.0Hz
Everything works perfectly until I set the host sample rate to 48000Hz which creates a fractional conversion ratio.
I get one sample of noise, I think it's from rounding errors it generates 1 less samples than I need for the current buffer fill, which could be any size as you know.
What is the best strategy in coping with these fractional sample rate changes when using a real-time buffer? Do I make 1 extra sample each frame and somehow wind back my internal processing by one sample the next time around?
I don't clear it every frame I just do what the example.cpp shows. Except of course I have an inflexible destination size.
Thanks.
Dave H.
Dave Hoskins. http://www.quikquak.com
- KVRAF
- 7897 posts since 12 Feb, 2006 from Helsinki, Finland
It was introduced by Pentium 4 and it's guaranteed to be supported on every 64-bit processor.
In essence, that means that just about every CPU from the past 15 years does support it.
- KVRian
- 872 posts since 6 Aug, 2005 from England
Thanks mystran, I just vaguely remember a discussion on KVR about guaranteeing support for SSE, but I guess that was a few years ago now...
Dave Hoskins. http://www.quikquak.com
- KVRian
- 872 posts since 6 Aug, 2005 from England
In the meantime does anybody know a conversion rate library where you ask for a certain amount of output data and it tells you back how much input it expects for that amount each frame?
Dave Hoskins. http://www.quikquak.com
- KVRian
- 872 posts since 6 Aug, 2005 from England
Ok, I’m currently adding the fractional input size to a counter, and when this overruns 1.0 I increase the input size. It seems to work OK. And always returns the correct number of samples. I need to test many different rates though.
Dave Hoskins. http://www.quikquak.com
- KVRAF
- 7897 posts since 12 Feb, 2006 from Helsinki, Finland
Keep in mind that unless your doing the computations in exactly the same way as the library, you'll accumulate some rounding errors that will eventually cause you to fall out of sync. Since trying to match rounding errors is not something you typically want to do, I'd highly suggest thinking about an alternative solution.
If you're doing something like sample playback, then the easiest approach is probably to feed the converter blocks of samples until you have enough output to satisfy your external block size. If there's excess, buffer it for the next block.
If you're trying to take real-time input, resampling it to another (fractional) rate, process and convert back, then you're pretty much doomed without a special purpose converter pair specifically designed for this.
- KVRian
- 872 posts since 6 Aug, 2005 from England
Thanks for the warning, yeah I thought it was a naive approach, I will probably replace it at some point I just wanted to test an OSC idea I had TBH.
Although it has been running OK for an hour with a ratio of 1.8354166666666667! - Nice.
Although it has been running OK for an hour with a ratio of 1.8354166666666667! - Nice.
Dave Hoskins. http://www.quikquak.com
- KVRAF
- Topic Starter
- 4021 posts since 7 Sep, 2002
r8brain-free-src wasn't designed for real-time SRC, so there's no "convenient" ways to use it for real-time SRC. But it does work for real-time SRC in practice judging by numerous reports. So, real-time SRC indeed requires "workarounds" not offered by the library out-of-the-box.
-
- KVRian
- 1273 posts since 9 Jan, 2006
Depending on the process it might be easier to switch internal sample rate relative to host sample rate, so 88200 for 44100 or other integer ratios and 96000 for 48000 etc. I'd avoid fractional ratios unless necessary
- KVRAF
- 7897 posts since 12 Feb, 2006 from Helsinki, Finland
Fractional "oversampling" (or "undersampling" for that matter) ratios are fairly easy to implement by solving the internal sampling instants in terms of the external sample clock once, then using sinc-gathers and sinc-scatters as a "reciprocal" pair of filters that can both use the exact same fractional offsets. I'm not sure if there are really any libraries that implement this, but it's totally robust (when implemented correctly, duh) at the cost of being somewhat slower (partly because of the scatters, but mainly because you lose a bunch of poly-phase optimisations that can be done in the integer ratio case).
It's worth it if the internal sampling rate is an intrinsic part of your effect, but not really otherwise.