external object for
multi-channel, multi-voice, multi-transposition granular
This Max/MSP object performs time granulation of sampled sound in
Input in the form of a fixed, pre-recorded sample buffer or an incoming signal
of user-specified length is used to randomly select segments of sound (grains)
whose durations (grain length) may be modified on-the-fly. The grains are
(amplitude-) enveloped and reconfigured each time a precursor comes to an end.
The granulation is performed in a user-specified number of streams (also known
as (aka) voices or layers): the more streams, the denser and thicker but also
the smoother the effect. An increase in streams also implies an increase in
processing time and is the main factor affecting real-time performance.
The streams may be subject to transposition whereby either a single
transposition offset is given and/or a list of semitone values
sent to the object forms the set from which a randomly-chosen value is selected
for each grain of sound output by the object.
Finally, each grain is routed to a randomly-chosen outlet (the number of which
is also user specified) allowing mapping onto an arbitrary number of
N.B. Most data passed to the object only has an effect when the DSP is
on. If you're getting strange behaviour/crashes, make sure the DSP
is on before you start interacting with the object.
mdeGranular~ object usage
The object takes the following arguments:
- The number of simultaneous streams (aka voices, layers) of grains ; this
is limited only by your computer's CPU power.
- The number of output channels; this will determine the number of signal
outlets the object has, i.e. there will be one for each channel you
As with most Max/MSP objects, various data can be sent to the left-most
- A bang toggles play/stop (aka on/off) state.
- An "on" message turns the granulator on.
- An "off" message turns it off: both on and off (as well as
bangs) work gracefully, i.e. with a fade up/down to avoid a
click. The length of the fade is the same as the grains' ramp
- A list sets the transpositions in semitones (default none, limited to
256) that each grain will then choose randomly from. Given
enough voices, sending the list 0,3,7, for example, will result in an
audible minor triad (assuming that the input is pitched
material). Note that transpositions may be negative and
floating point (i.e. microtonal).
- An OctaveSize and/or OctaveDivisions message will change the
temperament of the transpositions (once new ones are
received). Temperament will remain equal but you can move
away from the default temperament of 12 semitones in an
octave of twice the frequency. E.g. OctaveSize 3
OctaveDivisions 13 would create a tempered Bohlen-Pierce scale.
- A "set x" message sets the buffer (aka sample table, e.g. "set
granbuf") to be granulated, or the length of the buffer for live
granulation (e.g. "set ms1000"): If a number preceded by "ms" is
given, this will be the buffer length (in milliseconds) used to store
incoming signal samples (e.g. ms5000 for 5 seconds), otherwise the
name given is assumed to be that of an already existing sample buffer
object. Changing the buffer on the fly will probably result in a
click in the output so it's best to switch off the granulator first,
change the buffer, then switch it back on. N.B. for live buffers,
this message only sets the length of the allocated buffer that will be
used: to actually allocate memory for a live buffer use the
MaxLiveBufferMS message (see below). The minimum size for a live
buffer is 6ms. The default is a 1000ms live buffer.
NB In September 2013 this object was updated to the Max API
6.1.3. This meant fairly hefty changes to make the object work in the now
64 bit float (double) MSP environment. Most changes reflect the new buffer
accessing framework in MSP. An MSP buffer~ is still 32 bit (for backward
compatibility) so if granulating a static buffer~, its samples are first
copied over and promoted to 64 bit by mdeGranular~. This will mean that if
you change the contents of the buffer~ there will be no difference to the
granulator's output until you reuse the set message again. See also the
note about MaxLiveBufferMS below.
- A "setms x" message essentially does the same as a 'set ms...' message
but allows you to avoid the 'ms' prefix onto buffer sizes; so 'set
ms2000' == 'setms 2000'
- A "BufferGrainRamp x y z" message is useful for setting the buffer
(live or static), grain length, and ramp length simultaneously. When
you set these independently, checks are made to ensure you do nothing
that would cause a crash (e.g. try to put impose a ramp that's too long
for the grain length, or a grain length that's too long for the buffer
size). Because of this it's sometimes difficult to know which you
should set first: the required order depends on the current and desired
states. So using this method you can do all three at once and have no
execution order problems.
- A "MaxLiveBufferMS x" message sets the maximum length of the live
buffer (x, milliseconds). This should generally be set to the maximum
you will need for your whole performance (to avoid allocating memory
on the fly). In particular, because switching off the granulator is
not immediate (there is a ramp down to avoid clicks), you should
definitely wait after doing so (one second should be enough) and
before sending this message otherwise memory that has been
de-allocated might be read thus causing a crash. Default = 10 seconds.
NB Since the update to Max API 6.1.3 and the 64-bit MSP
environment, the internal buffer is now used for copying static MSP
buffer~ samples over from 32-bit to 64-bit, hence the MaxLiveBufferMS
size must also accommodate the largest MSP buffer~ you'll want to
granulate in a performance.
- Signal sent to the left inlet will be used for live granulation or
ignored if the granulator is currently using another buffer (as
determined by the "set" message, see above).
- A "livestop" message stops recording the incoming signal so
that granulation proceeds with what is already in the buffer
(a granular form of sample and hold).
- A "livestart" message starts recording incoming signal again.
- A "print" message prints the state of the granulator to the Max window
(for debugging purposes).
- A "DoGrainDelays" message will make each voice (aka layer of grains)
pause slightly (randomly between 0 and 200% of the grain length) when
starting the next grain; this should smooth out the granulation
process and avoid all grains starting/stopping at almost the same
time. This is done automatically when the granulator is started and
is particularly useful when switching on-the-fly from very short grain
lengths to very long grains lengths.
- A "SmoothMode" message is related to DoGrainDelays but here
the delays are no longer random. Instead they're spread out
evenly--(and with no grain length deviation--over a grain
length e.g. if there are 5 active voices, each one will wait
1/5 of a grain length before restarting. NB if ActiveVoices
is changed, this will not retrigger so 'smoothness' may be
interrupted. This function may also cause a click in output
so it is envisaged that the object is off or the amp is at 0.
Bear in mind that the smoothness of the result is still
dependent on the material being granulated. Also consider
that if you're using a live buffer, then its length must be
at least a little greater than twice the grain length (or
more if transposing upwards) because we avoid the portion of
the live buffer that will be written into whilst the grain is
- A "Portion position% width%" message sets the start/end points
in the buffer by passing values in percentages: position% will
set the middle point between start (0) and end (100), as
determined by width% (0-100). These default to 0 and 100
- For convenience, a "PortionPosition x" message sets the
position only of the Portion algorithm. Similarly
"PortionWidth x" sets the width only. In each case the other
parameter remains at its previous value.
- A "RampLenMS x" message (where x is the new ramp length in
milliseconds) will change the ramp length. This is only
possible when the granulator is off (and has finished it's
fade out). The default ramp length is 10ms and the minimum
- A "RampType x" message will set the type of ramp up and down; x can be
one of the following standard windows (all case sensitive):
HANN (or HANNING: the default, a typical bell-shaped window),
TRAPEZOID (straight line ramp),
RECTANGULAR (no ramp at all),
- A "MaxVoices x" message will set the maximum number of voices (layers)
running. This may also cause a click in output so it's best sent when
the granulator is off.
- An "ActiveVoices x" message will set the number of the maximum voices
that are actually playing. This may be safely changed on the fly.
Changing this will not instantly affect the output however as the
grains are only deactivated once they have got to the end of their
- An "ActiveChannels x" message will set the number of output channels
used. This should of course be less than the number of output
channels set as the object argument.
- A Warnings (1 or 0, default 1) message will toggle between
printing useful warnings or not to the Max window
i.e. "Warnings 0" means the object should remain silent no
matter what you tell it to do and how much sense that makes
(and whether it ignores you or not).
The rest of the inlets, numbered from left to right, are as follows. The
messages which can be sent to the leftmost inlet to accomplish the same thing
are in square brackets and are case sensitive.
- Transposition offset in semitones (default none): This may be
fractional; it is added to the list of transpositions sent to the left
inlet (see above), or simply transposes all the grains if no
transposition list is given.
- Grain length in milliseconds (default 50).
- Grain length deviation (as a percentage) of the grain length (plus or
minus, default 10%); i.e. if anything other than 0, the grain length is
randomised by an amount between plus or minus the deviation
- The minimum start point in the input buffer (fixed or live) in
milliseconds (default 0). The actual start point is a function of the
grain length, and the start and end points (see below) and is randomly
chosen to fit anywhere within these points.
- The maximum end point in the buffer in millisecs (the default is the end
of the buffer). N.B if end < start then the buffer will be granulated
backwards. If the difference between these two is too small for the ramp
up and ramp down to be accomplished, no grains will be
- The "density" of the grains (as a percentage). 100% means a grain will
start immediately every time the previous one ends, 50% means one in two
grains (determined randomly) will produce no output. (Default
- Grain amplitude (>=0 and <= 100, default 0.5). This is a
straight amplitude scaler for each grain, i.e. no account is
taken of how many voices there are. N.B. when using MIDI faders,
the 7-bit step between values is often large enough to create a
slight but audible click in output. This is corrected in
mdeGranular~ by interpolating from the last to the new amplitude.
The side-effect is that new amplitudes will not be accepted for
an "audio tick's worth" of samples.
mdeGranular~ 1.1 (external and help file) for Max API 6.1.3 and above. 64
bit and more stable than the Universal Binary version below.
Old mdeGranular~ archive (external and help
file) for Max/MSP pre Max 6.1.3 on OS X (Universal Binary)
N.B. On older systems this ZIP file needs to
be unzipped with /System/Library/CoreServices/BOMArchiveHelper in
order for resource forks to be preserved. If you get the error
"mdeGranular~: no such object" when you open the help file in Max/MSP,
unzip the downloaded archive again using the above application.
mdeGranular~ external for Windows
Max/MSP (thanks and kudos to Giacomo Lepri for compilation services)
mdeGranular~ help file
* Updated to Max API 6.1.3: fairly hefty changes to make the object work in
the now 64 bit float (double) MSP environment. The object should also
behave itself better when the dac~ is turned on and off and/or receive
messages that normally would need the dac~ to be on before being processed
correctly. Most changes however reflect the new buffer accessing
framework. The MSP buffer~ is still 32 bit (for backward compatibility) so
if granulating a static buffer~, its samples are first copied over and
promoted to 64 bit. This will mean that if you change the contents of the
buffer~ there will be no difference to the granulator's output until you
reuse the set message again, thus triggering the samples copy.
* 3/10/11: added BufferGrainRamp message/method
* 19/5/11: fixed bug that caused crash on reinitialisation of object
* made some changes to allow resumption of previous state (without crashes)
when the DSP is turned off and back on again
* migrated project to latest SDK (5.1.1)
* fixed a bug that caused a crash when quickly changing ramp lengths from
very long to short;
* added the Portion, PortionWidth, and PortionPosition messages to more
easily control buffer granulation points;
* made the ms prefix to setting live buffer sizes no longer necessary by
introducing the setms message e.g. 'setms 2000' instead of 'set ms2000'
(but ms prefix still works);
* handled the post bug that in Max5 refuses to add new lines (thus screwing
up warning/error messages);
* fixed bug in grain start/end setting that added current live index even
when we were processing a static buffer;
* separated out the maxmsp and pd interface parts into separate c files
and created a common header.
* added Warnings message to turn on/off printing to max window (for Kim
* added OctaveSize and OctaveDivisions messages for non-standard tunings
* fixed bug that stopped grain amplitude from reaching 0
* added OSX USB support
* fixed RAND_MAX bug in between function
Last modified: Friday, 08-Mar-2019 15:18:11 CET