Fractals are objects with (potentially) infinite recursive substructure. In this mini-project, we’ll practice writing two kinds of fractals using numeric recursion:
You have likely seen visual fractals like Sierpinski’s Triangle or the Mandelbrot Fractal at some point in your life. However, musical fractals are perhaps a new concept. Music educator Adam Neely explains how musical fractals work where by creating by playing repetitions of songs at high enough frequencies that the sound of these repetitions themselves become the original song in question!
Scamper does not possess a high-power enough sound engine to playback so many notes at once. However, we can still build musical fractals to a reasonable depth and appreciate the effect!
First, we will build three visual fractals, the last of which should be your own design! We will implement these fractals as three functions:
(cantor-set width height fill color n)
draws a Cantor Set of depth n
with the given visual properties.
In particular, width
and height
are the dimensions of a single bar of the Cantor Set.(serpinski-carpet length fill color n)
draws a Serpinski Carpet of depth n
with the given visual properties.
In particular, the length
property denotes the size of the entire image, not just one of the black squares.(my-fractal ... n)
draws a fractal of your own design to depth n
.Below are examples of various cantor-set
and serpinski-carpet
calls.
Note that cantor-set
with n=0
draws nothing and serpinski-carpet
with n=0
draws a white box with dimensions length
.
(cantor-set 100 10 "solid" "green" 1)
(cantor-set 100 10 "outline" "blue" 2)
(cantor-set 100 10 "outline" "purple" 3)
(cantor-set 100 10 "solid" "black" 10)
(serpinski-carpet 100 "solid" "blue" 1)
(serpinski-carpet 100 "outline" "green" 2)
(serpinski-carpet 100 "solid" "black" 3)
(serpinski-carpet 300 "solid" "purple" 5)
For my-fractal
, you should design a fractal by composing elementary shapes recursively in a novel way.
Here are the requirements for my-fractal
:
my-fractal
should behave recursively according to the depth parameter n
.my-fractal
should take some parameter that determines the size of some aspect of the image, e.g., an important subfigure as in cantor-set
or the overall image as in serpinski-carpet
.Otherwise, feel free to have fun designing a cool looking fractal!
In the previous part, our visual fractals consisted of patterns that varied by size and position. With multiple “dimensions” to play with in our patterns, we are able to create some obvious, yet compelling effects with recursion. With aural fractals and our current musical vocabulary, there are less dimensions to play with. In particular, we can manipulate:
However, observe that our MIDI note values are discrete, i.e., they are integers and not fractional values. Furthermore, their range is highly restrictive: integers in the range 21–108. These limitations are problematic for our fractals in that we’ll quickly run out of possible MIDI values as our recursion gets deeper.
To this end, we introduce a new musical composition primitive, note-freq
.
(note-freq freq dur)
is a musical composition consisting of a note played at the given frequency, freq
for the provided duration dur
.
Recall from our reading on sound and music that the pitch of a sound is governed by the frequency of vibrations of that sound’s movement through space, i.e., its wave.
The unit for frequency is hertz and with note-freq
, we can create pitches that only vary in sound by miniscule amounts, e.g.,
(import music) ; MIDI note 69 (A4) (note-freq 440 qn) (note-freq 450 qn) (note-freq 460 qn) (note-freq 470 qn) (note-freq 480 qn) ; (Roughly) MIDI note 70 (B4) (note-freq 490 qn)
With note-freq
, we can create interesting sound recursive fractals by dividing up the frequency and duration on each recursive call, just like we did with size in our visual fractals!
To assist in dividing up durations, first write a helper function (div d n)
that takes a duration d
and returns that duration but divided by n
.
To write this function, remember that numerator
and denominator
retrieve the appropriate components of a duration value and dur
create a new duration when given those components:
(import music) (numerator qn) (denominator qn) (define three-eights (dur 3 8)) (numerator three-eights) (denominator three-eights)
With this helper function in mind, let’s write our two musical fractals!
(dominoes freq d n)
creates a musical fractal at depth n
that operates recursively as follows:
n = 0
, nothing is played, i.e., the empty composition is given (via the empty
constant).n > 0
, the following is played in sequence:
freq
and duration d
dominoes
composition of depth n - 1
at half the frequency and duration.(raindrops lo hi d n)
creates a musical fractal at depth n
.
It is assumed that lo
and hi
are valid frequencies and lo < hi
.
raindrops
operates recursively as follows:
n = 0
, three notes are played in sequence, all at duration d / 3
:
lo
.hi
.(hi + lo) / 2
, i.e., the frequency between lo
and hi
.n > 0
, three raindrops
compositions of depth n-1
are played, each of which with duration d / 3
.
To describe the frequencies that these composition take, break up the range of frequencies into four evenly spaced parts: lo
, 1qrt
, mid
, 3qrt
, and hi
:
raindrops
composition with frequencies lo
and 1qrt
.raindrops
composition with frequencies 3qrt
and hi
.raindrops
composition with frequencies 1qrt
and 3qrt
.Finally, on top of these two musical fractals, write a final fractal, my-musical-fractal
of your own design.
Like with the visual fractal, my-fractal
:
my-musical-fractal
should behave recursively according to the depth parameter n
.my-musical-fractal
should take some parameter that determines the duration and frequency of composition in some way like dominoes
and raindrops
.cantor-set
serpinski-carpet
my-fractal
dominoes
raindrops
my-musical-fractal