First, let's import everything we need, namely the fibonaccistretch
module (which you can find here):
In [ ]:
%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:
In [ ]:
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:
In [ ]:
# "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]
):
In [ ]:
# "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)
We can contract rhythms as well using negative numbers as our stretch_factor
. Let's try that with "Chan Chan" by the Buena Vista Social Club:
In [ ]:
# "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:
In [ ]:
# "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):
In [ ]:
# "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)
We can apply contractions simply by supplying a target rhythm that is shorter in length than the original rhythm. Here's an example with Beyonce's "Hold Up":
In [ ]:
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:
In [ ]:
# "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.)
In [ ]:
# "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:
In [ ]:
# "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!
In [ ]: