MSP Polyphony Tutorial 3: Granular Synthesis
Click here to open the tutorial patch: 03hGranularSynthesis.maxpat
Contents |
Granular synthesis
In this tutorial we'll look at using the poly~ object to generate large amounts of polyphony in order the play the contents of one buffer~ of sample data. We'll leverage the ability of MSP to play sample data from the same buffer~ at multiple arbitrary speeds and time points to explore the technique of granular synthesis
Put simply, granular synthesis is the use of very short (or, sometimes, less short) sonic events called 'grains' to generate complex textures. While the musical and written literature on the technique is beyond the scope of this tutorial (see Curtis Roads' Microsound (MIT Press: 2004) for a great exploration of this topic), we'll cover the basics here. While classic granular synthesis relies on the use of very small amounts of wavetable data, the technique we'll explore in this tutorial uses sample data taken arbitrarily from soundfiles.
In our tutorial patcher, we'll create an algorithmic playback system based on constrained random values to control the following parameters of a polyphonic sample playback engine: rate, onset point, duration, pitch, amplitude. We'll also look at how adjusting envelopes changes the sonic output.
Experimenting with the patcher
Take a look at the tutorial patcher. There are several numbered
areas, each of which controls part of our granular synthesis
engine. The patcher area labeled 1 is the grain emitter
proper: a metro object schedules and fires bang messages
into a poly~ object that has loaded 100 voices of an
abstraction named polygrain~. Area 2 allows us to
check our CPU usage depending on the parameters of our synthesizer.
Area 3 and 4 set the synthesis parameters - the
sample we're using, which area of it to draw from for grains,
and the parameters of the grain playback system in
the polygrain~ abstraction.
- In patcher area
1, turn on the audio with the toggle object
connected to the dac~. Turn up either one of
the gain~ sliders; the other should follow along.
At the top of the patcher, click the button object a few
times and listen to the results. Sending a bang into
the poly~ object generates a single 'grain' of audio.
Turn on the metro object by clicking the toggle at
the top of the patcher.
The poly~ object in our patcher generates grains: single
bursts of sample playback which we can control dynamically by
adjusting parameters. The metro and button objects
control the grain emitter. Each time the metro fires,
it sends a bang into the poly~, prepended by
the note message, which assigns the bang to the
first available voice within the poly~. In addition,
each bang from the metro object schedules the
next one by adjusting the speed of the metro.
The random object generates a random value which is
then put through a scale object with a variable output
range, defined by the speedmin and speedmax parameters
found in patcher area 4.
Checking CPU
- With the grain emitter enabled (i.e. the metro object set
to run), turn on the metro in patcher area 2.
The number box at the bottom of the patcher logic should
output a number. Turn off the grain emitter at the top and watch
the results. Turn it on again.
The adstatus object allows us to control and view aspects
of the MSP audio driver currently running. All of the viewable
attributes of the Audio Status window (available under the
Max Options menu) can be accessed via the adstatus object.
The cpu mode of the adstatus object (set by its argument)
instructs the object to receive bang messages and output
the current CPU usage of MSP. Notice that when the grain emitter
is turned off, the CPU usage drops to 0.. This is because
our poly~ abstraction mutes itself when its playback has
finished. When no notes are firing, all of the copies of
the poly~ abstraction should be muted.
Adjusting parameters
- In patcher area
3, highlight an area of the waveform~ objects
to select part of the buffer~ named thegrain.
Notice that when you drag on either of the waveform~ objects,
both of them highlight in the same regions. The rightmost outlet
of the waveform~ object allows us to link them
together so that you can use more than one of the objects to work
with a multi-channel buffer~. Load a different sample using
the message boxes above the buffer~ object and
highlight different regions of the sample. The highlighted regions
of the buffer~ controls where the grain emitter draws its
sample data.
- In patcher area
4, use the preset object to try out
different parameters for our grain emitter, then try entering your
own values. The Grain rate number boxes control the
speed range of the metro in patcher area 1.
The Grain duration controls the ranges for how long each
grain plays for inside the poly~. The Grain pitch
values provide a range for what speed the grains play at.
The Grain amplitude controls set the volume range of the
grain emitter, and the Grain slope sets the sharpness of
the attack and decay on each grain's envelope. Notice how different
densities of grains changes the sound as well as the CPU usage of
the grains.
Before we look at our poly~ abstraction, notice the
effect of longer and shorter grain rates and durations on the
CPU usage. Longer grain durations and shorter grain rates result
in more voices inside the poly~ being active at any
one time - either they are fired more frequently, or they
take longer to 'free' themselves, or both. The result is a
higher CPU usage.
- In patcher area
1, enable the toggle object
attached to the message box labeled parallel $1.
Restart the audio by turning on and off the dac~. Notice
the effect, if any, on the CPU.
Depending on your computer architecture, you can take advantage
of multiple cores in your computer's CPU (or multiple processors
if you have a multi-processor machine) by dividing the poly~ object's
resources over multiple threads. In essence, this divides
the instances of the poly~ object across the different
cores or processors of your computer, allowing sets of voices
to run in parallel. Depending on your computer's CPU architecture,
this may provide a significant boost in performance.
Inside the patch
- Double-click the poly~ object to view an instance of the
abstraction named polygrain~. Take a look around the patcher.
The polygrain~ abstraction recieves a single bang
(via the in object at the top of the patcher) and uses it
to generate a grain of audio, using the MSP logic at the bottom
of the abstraction. The trigger object at the top of the
patch clearly sets up the order of events for generating our grain:
First, the thispoly~ object receives a mute 0
and 1 message in immediate succession. This turns on (unmutes)
the signal processing in the instance, and sets it's state to 'busy',
so that it won't receive any more messages until the grain is finished.
Next, a bang is dispatched to generate a random amplitude
for the grain, which goes into the right side of the *~ object
labeled 'how loud is this grain?'. This *~ controls the
scaling for the output of the line~ object above that sets
the grain envelope.
Third, a random pitch is selected which is transformed into
a duration multiplier for the line~ objects controlling
the playback of the sample and its amplitude envelope. The !/ object
divides the incoming pitch into 1., so that a requested
pitch of 2. tells the objects downstream to multiply their
durations by 0.5 (half as long, and up an octave).
Fourth, a random duration is generated, which sets up the parameters for the line~ objects so that they generate the appropriately scaled and offset values for the grain length.
Finally, a grain is triggered by generating a random start point
based on the highlighted areas in the waveform~ object in the
main patcher. This bang eventually generates two messages
which command the two line~ objects to generate the playback
curve for the play~ object and the amplitude envelope for
the *~ objects.
Once the 'envelope' line~ is finished, it sends a bang
to mute the instance and set it to 'free' (0), so it
can receive a new message.
- Under the File menu in Max, select Modify Read Only.
This will allow you to unlock the copy of the simplegrain~ abstraction
you are viewing. Unlock the patcher, and place 'watchpoints' on some
of the patchcords to monitor their values. In the Watchpoints
window, you should see how different values in the grain settings
in the main patcher translate into values for the synthesis algorithm
at work here.
Summary
The poly~ object allows you to have a large number of instances
of a single, simple MSP patcher. You can use send
and receive to communicate to all instances of a poly~
abstraction, which can be distributed across multiple cores or
processors with the parallel message.
The adstatus object allows you to access and change
aspects of the MSP audio driver; the cpu argument to the
object lets you see how much of your computer's CPU you are using
with a patcher.
See Also
adstatus - Report and control audio driver settings