Closed woolgathering closed 3 years ago
Is shifter
a RubberBandStretcher
object pointer?
If you have constructed it in offline mode, then time-stretching is a two-pass procedure - you must go through the input file block by block and pass each block to the study
method (setting the final
argument to true
for the last block) first, before then going through and passing each block to process
.
It is study
that determines where the transient sync points should go for proper synchronisation in the subsequent process
calls - without that, the offline process has no stretch profile to follow.
(If this does turn out to be the cause of the issue, then I'll have to see if I can make it clearer in the documentation!)
Ah, that makes sense and it was it.
The documentation in setTimeRatio
makes it seem like it is possible to run this without study
(since it also runs in realtime). To be clear, one needs to call study
in offline mode for the timeScale to do anything but doesn't need to call study
in realtime mode?
That's correct - study
is for offline mode only.
In offline mode: construct and configure, set time and pitch ratios, study the file in blocks, process the file in blocks (output is produced as you run process). You can't change the ratios after the first call to study.
In realtime mode: construct and configure, then process the stream in blocks, setting time and pitch ratios whenever you like (output is produced as you run process, though as you correctly say, handling latency can be tricky). No study.
I've added some notes on this to the inline docs. Closing the ticket.
I'm not sure if it's a usage issue or what but there are two problems:
setTimeRatio
does nothing to the output. Setting this to any value has no effect.setPitchScale
only resamples. I.e. if set to 2, there is an octave shift upwards but the duration of halved.I've tried using a circular buffer for input/output, reading/writing directly to and from vectors, arrays, juce::AudioBuffer, etc. The sample values are not exactly the same but are extremely close which makes me think it is a function of the input being processed by whatever FFT process and being resynthesized.
I'm attempting to do this all offline so I don't have to deal with latency since time-stretching is inherently non-realtime.
A toned-down example with lots of experiments removed:
This simply ends up writing the input buffer to the output buffer when
shifter->setPitchRatio(1)
andshifter->setTimeScale(x)
wherex
is literally any number.