A time-stretcher such as Rubber Band Library has to be handled a little differently from a typical audio effect.
When speeding up or slowing down audio, there is by definition a difference between the input and output "rates" of the processor. If you supply N samples as input to the processor, then you will get more than N (when slowing down) or fewer (when speeding up) as output.
This must be the case for any audio time stretcher library, but on top of this, with Rubber Band the effective rate can also differ locally depending on the locations of detected features such as percussive transients, which it usually tries to pass through unmodified.
This means that the input and output rates are not always in a stable ratio: the ratio you set behaves like a long-term average, rather than a fixed ratio for every processing block.
A consequence of this is that you cannot just provide a
certain number of samples at the input and expect to see a fixed
number of samples at the output. This is true even
if you are using the processor only for pitch-shifting, and in
fact it is true even if you have the time and pitch ratios both set to
1! After supplying samples to the input with process
, you
must always query how many samples have now been made available at
output
using available
. See this
discussion for more details of how that might work when
pitch-shifting, as well as the examples below.
For real-time use especially, it may be simplest to use Rubber Band if you are able to integrate it using a "pull" configuration rather than a "push" one, so that the number of samples you supply to it for a given number of output samples is allowed to vary freely. That is:
available
), as there may be some in its internal buffers;getSamplesRequired
);process
), receives the available output (retrieve
), and repeats if necessaryThis structure can be seen at work in the Mini Example with Qt and Sonic Visualiser code examples below.
Playback is dropping out because the stretcher doesn't return enough samples in my play callback. This is usually the problem described in the conceptual notes above. Review those.
Output from real-time mode is not aligned with the
timing I expected. Check the documentation
for getPreferredStartPad
and getStartDelay
. You
need to pad the start of the input with the number of samples returned
by getPreferredStartPad
,
and drop from the start of the output the number of samples returned
by getStartDelay
. Offline
mode does this for you, but real-time mode doesn't.
I don't know which combination
of RubberBandStretcher::Option
s to use. Some suggestions:
OptionProcessRealTime |
OptionEngineFaster | OptionPitchHighConsistency
OptionFormantPreserved
when dealing
primarily with vocals or solo instrumentsOptionProcessRealTime |
OptionEngineFaster
OptionEngineFaster
with OptionEngineFiner
OptionProcessOffline | OptionEngineFiner |
OptionPitchHighQuality
study
OptionProcessOffline |
OptionEngineFiner
study
Finally, if you're doing large-scale data-augmentation
for machine learning, please default to not
using OptionEngineFiner
or the -3
option to
the command-line tool. The Finer engine uses a lot more energy and is
probably unnecessary for this task.
Here are some code examples. We don't recommend trying to use any of these as a cut-and-paste source, but they may help as documentation to address specific points of concern.
Illustrative examples published by Breakfast Quay:
Third-party examples from open-source code using Rubber Band Library: