I used to think the classic stutter DJ effect was one of the trademark sounds of Pluggo. No doubt it has been around a lot longer than that, and maybe even in acoustic music somehow. But about the time I started going along to gigs and hearing people use it (all over the place) I found out that there was a Pluggo plug-in called “Stutterer” that pretty much does it all. That plugin survives to this day as a Max for Live device.
Like all sounds which come and go into and out of people’s lives, there is a standard life cycle in play:
Phase 1 (Spotted in the wild): “Oh my god, that sounds so awesome! What is it?”
Phase 2 (Acquisition): “Aha! Now I have this awesome cool trick that NOBODY ELSE knows about, and I’m going to slather it on everything.”
Phase 3 (Disillusion): “Ugh, it’s all over everything. I need to get rid of this crap. I’m sick of it.”
Phase 4 (Reconciliation): “Hmm... Yeah - mixing it in very subtly every now and then and changing it around a lot can be pretty effective”
I never went through this with the stutter effect much, because I never really liked the stutter effect itself. But I did look at how it was made, and I found a new use for the object which was built in MSP to do this.
And so, allow me to present the stutter~ object.
If you look at the help file for the stutter~ object, you can discern its primary function as a stuttering engine. Turn off auto grab and make the grab size larger. Now you can bang on the playback speed and bang the stutter~ object to copy the grab size to the playback buffer and cycle through it
The stutter~ object implements a ring buffer and writes audio history to it. In other words, it always holds the last number of samples in memory, and is constantly updating it, so the oldest sample in grain size is dropped when the newest sample is added. When you trigger it by banging it or sending it a number of samples to grab, it copies that number of samples over to another buffer and makes them available for playback. You can also tell it to copy the samples over to an external buffer~ or polybuffer~ in your patcher.
So it’s like a little musical memory. What I then did was start chucking huge numbers at grain size. What if it could remember the last 10 seconds?
Once you start doing this, you’ll need to give the stutter~ object more memory to use. Typically I’ll have it set up like this:
So this means I am telling the stutter~ object to have a maximum size of 500000 samples, start with a default grain size of 11025 samples (250ms @44.1k), invert trigger polarity, and copy 256 samples per perform loop over to the playback buffer. This last arg might seem to be a bit strange - what the hell is a perform loop?
Without going into a bunch of arcane MSP external detail, let’s just say this object is OLD. You need to tell it to up its game in the performance department if it is going to keep up with you moving larger chunks of audio around.
My patcher and favourite use of the stutter~ object uses the global transport to stay in sync with itself and set tempo. I want to be able to grab bits of audio from places and play them back in sync with the rest of my code.
Or not. You can grab any length of time from the stutter~ object.
Here’s how it works - If you choose to grab a number of samples which is an integer multiple of some metrical time element (as measured in samples) and then play it back, it might not be exactly offset in your bar correctly but it will loop perfectly as long as you remain at the same tempo.
If I choose to grab 1 bar of history at 120 bpm with an SR of 44100, then I grab 88200 samples. No matter where in the bar sample 1 is, it will always loop in sync with my bar as long as I do not change the tempo (or the sample rate).
So it’s in sync - I don’t need to worry in the slightest about quantizing the record start or lining everything up with 1 in the bar. The only time I might need to worry about where beat 1 starts is if I wish to create a “clip” out of my loop, and change the tempo (hint: the groove~ object )
Most people I’ve given this looper to don’t like the fact that it seems to work in reverse. The way I have presented it is that you do not start “recording” a loop into it - rather, you wait until you have played something and then copy it from history. Personally I find this more interesting in performance. It means I always have the ability to grab something which happened rather than consciously setting up the grab or missing things that go by because I didn’t hit the record button.
You can make the patcher act as a more typical looper by delaying the grab. So if I want to “start recording” a 2 bar loop, I delay grabbing the loop from history until 2 bars have passed. Again, accuracy doesn’t matter when it comes to the exact timing of things, as long as you copy a “metrical” amount of samples it will stay in sync.
Here are some other things you can do with this - I'll leave them as an exercise for the reader.
- Set it up to work with polybuffer~ so you can catch multiple loops and layer/arrange them.
- Add ramps to the playback stage so you can de-click.
- Implement pitch and time on the playback so you can change tempo.
- Spread the looper out over multiple MFL devices so you don’t end up saturating an output stage.
Check out the entire "My Favorite Object" series: bucket