by David Su
Here are some audio examples of the Fibonacci stretch algorithm in action. This notebook and its associated code are also available on GitHub.
Fibonacci Stretch is a method of time-stretching an existing audio track such that its rhythmic pulses become expanded or contracted along the Fibonacci sequence, using Euclidean rhythms as the basis for modification. Inspiration came initially from Vijay Iyer's article on Fibonacci numbers and musical rhythm as well as his trio's renditions of "Mystic Brew" and "Human Nature".
%matplotlib inline
import pardir; pardir.pardir() # Allow imports from parent directory
from fibonaccistretch import fibonacci_stretch_track
And let's also define some variables for convenience:
tresillo_rhythm = [1,0,0,1,0,0,1,0]
For our first example we'll stretch Michael Jackson's "Human Nature", off of his 1982 album Thriller.
We're using the tresillo rhythm as the original_rhythm
and a stretch_factor
of 1, which means [1,0,0,1,0,0,1,0]
(with pulse lengths [3,3,2]
) will get expanded to [1,0,0,0,0,1,0,0,0,0,1,0,0]
(with pulse lengths [5,5,3]
), as each pulse length is scaled along Fibonacci sequence by an index of +1:
# "Human Nature" stretched by a factor of 1 using default parameters
fibonacci_stretch_track("data/humannature_90s.mp3",
original_rhythm=tresillo_rhythm,
stretch_factor=1,
tempo=93.0)
With a stretch_factor
of 2, the tresillo rhythm [1,0,0,1,0,0,1,0]
(with pulse lengths [3,3,2]
) is expanded to [1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0]
(with pulse lengths [8,8,5]
):
# "Human Nature" stretched by a factor of 2
fibonacci_stretch_track("data/humannature_30s.mp3",
original_rhythm=tresillo_rhythm,
stretch_factor=2,
tempo=93.0,
overlay_clicks=True)
# "Chan Chan" stretched by a factor of -1
fibonacci_stretch_track("data/chanchan_30s.mp3",
original_rhythm=tresillo_rhythm,
stretch_factor=-1,
tempo=78.5)
(Note that although we do end up with a perceptible difference (the song now sounds like it's in 7/8), it should actually sound like it's in 5/8, since [1 0 0 1 0 0 1 0]
is getting compressed to [1 0 1 0 1]
. This is an implementation detail with the Euclidean stretch method that needs to be fixed.)
In order to get musically meaningful results we generally want to supply parameters that make musical sense with our input audio (although it can certainly be interesting to try with parameters that don't!). One of the parameters that makes the most difference in results is the rhythm sequence used to represent each measure.
Here's Chance the Rapper's verse from DJ Khaled's "I'm the One", with a custom original_rhythm
that matches the bassline of the song:
# "I'm the One" stretched by a factor of 1
fibonacci_stretch_track("data/imtheone_cropped_chance_60s.mp3",
original_rhythm=[1,0,0,0,0,1,0,0],
stretch_factor=1,
tempo=162)
We can define both a custom target rhythm as well. In addition, neither original_rhythm
nor target_rhythm
have to be Fibonacci rhythms for the stretch algorithm to work (although with this implementation they do both have to have the same number of pulses).
Let's try that out with the same verse, going from an original rhythm with 8 steps (i.e. in 4/4 meter) to a target rhythm with 10 steps (i.e. in 5/4 meter):
# "I'm the One" in 5/4
fibonacci_stretch_track("data/imtheone_cropped_chance_60s.mp3",
original_rhythm=[1,0,0,0,0,1,0,0],
target_rhythm=[1,0,0,0,0,1,0,0,0,0],
tempo=162,
overlay_clicks=True)
fibonacci_stretch_track("data/holdup_30s.mp3",
original_rhythm=[1,0,1,0,0,1,0,1],
target_rhythm=[1,0,0,1,0,1],
tempo=82)
As another example, we can give a swing feel to the first movement of Mozart's "Eine kleine Nachtmusik" (K. 525), as performed by A Far Cry:
# "Eine kleine Nachtmusik" with a swing feel
fibonacci_stretch_track("data/einekleinenachtmusik_30s.mp3",
original_rhythm=[1,0,1,1],
target_rhythm=[1,0,0,1,0,1],
tempo=130)
It works pretty decently until around 0:09
, at which point the assumption of a metronomically consistent tempo breaks down. (This is one of the biggest weaknesses with the current implementation, and is something I definitely hope to work on in the future.)
Let's also hear what "Chan Chan" sounds like in 5/4:
# "Chan Chan" in 5/4
fibonacci_stretch_track("data/chanchan_30s.mp3",
original_rhythm=[1,0,0,1,0,0,0,0],
target_rhythm=[1,0,0,0,0,1,0,0,0,0], # Also interesting to try with [1,0,1]
tempo=78.5)
We can also work with source audio in other meters. For example, Frank Ocean's "Pink + White" is in 6/8. Here I've stretched it into 4/4 using the rhythm of the bassline, but you can uncomment the other supplied parameters (or supply your own!) to hear how they sound as well:
# "Pink + White" stretched by a factor of 1
fibonacci_stretch_track("data/pinkandwhite_30s.mp3",
beats_per_measure=6,
tempo=160,
# 6/8 to 4/4 using bassline rhythm
original_rhythm=[1,1,1,1,0,0],
target_rhythm=[1,1,1,0,1,0,0,0],
# 6/8 to 4/4 using half notes
# original_rhythm=[1,0,0,1,0,0],
# target_rhythm=[1,0,0,0,1,0,0,0],
# 6/8 to 10/8 (5/4) using Fibonacci stretch factor of 1
# original_rhythm=[1,0,0,1,0,0],
# stretch_factor=1,
overlay_clicks=True)
Download the Fibonacci stretch code from GitHub and play around with it yourself!