Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pedalboard.time_stretch for time stretching. #249

Merged
merged 4 commits into from
Sep 12, 2023
Merged

Conversation

psobot
Copy link
Member

@psobot psobot commented Sep 8, 2023

Pedalboard already includes Chris Cannam's excellent Rubber Band library for its PitchShift plugin. This PR adds a tiny utility function, called pedalboard.time_stretch, to expose Rubber Band's other useful bit of functionality: time stretching.

Note that as time stretching changes the length of the audio, this functionality is exposed as a separate standalone function, rather than as a Plugin subclass, and as such cannot be included in Pedalboard effects chains. However, getting time stretching "for free" by adding ~128 lines of glue code and tests seems pretty worthwhile.

@psobot psobot added the enhancement New feature or request label Sep 8, 2023
Copy link

@rabitt rabitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a couple of naming nits, otherwise looks good!

* provided for every sample input, but this assumption does not hold true
*/
static juce::AudioBuffer<float>
timeStretch(const juce::AudioBuffer<float> input, double sampleRate,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this function is called timeStretch, but looks like it can do time stretching + pitch shifting at once?

@psobot psobot merged commit 8a0dcfb into master Sep 12, 2023
@psobot psobot deleted the psobot/time-stretch branch September 12, 2023 17:01
@f0k
Copy link

f0k commented Jan 18, 2024

@psobot: Thanks a lot for doing this, very useful! In extending some augmentation pipeline, I noticed that the time_stretch() function is slower and gives different results than the PitchShift plugin:

In [1]: import numpy as np

In [2]: import pedalboard

In [3]: x = np.sin(2 * np.pi * 0.001 * np.arange(250*512)).astype(np.float32)

In [4]: %time y1 = pedalboard.time_stretch(x, 44100, pitch_shift_in_semitones=2)
CPU times: user 371 ms, sys: 15.3 ms, total: 386 ms
Wall time: 385 ms

In [5]: %time y2 = pedalboard.Pedalboard([pedalboard.PitchShift(semitones=2)])(x, 44100)
CPU times: user 193 ms, sys: 0 ns, total: 193 ms
Wall time: 193 ms

In [6]: import matplotlib.pyplot as plt

In [7]: plt.plot(y1.squeeze()[:1000])
Out[7]: [<matplotlib.lines.Line2D at 0x7ff160723460>]

In [8]: plt.plot(y2.squeeze()[:1000])
Out[8]: [<matplotlib.lines.Line2D at 0x7ff160738160>]

plot

Off the top of your head, do you know the reason? Setting high_quality=False gives a similar speed to PitchShift, but yet another result (a third one). I'd just like to understand if I'm missing out on anything when switching from PitchShift to time_strech() (for the use case when I actually need both stretching and shifting).

/edit: Ok, PitchShift uses rubberband in real-time mode and primes it with a second of silence, while time_strech() uses rubberband in offline mode, analyzing the full audio buffer before computing the output. This is enough to explain the difference, and I would assume pitch_shift() generally gives better results at the expense of additional processing time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants