«Stutter tutorial» by snappizz

on 01 Feb'16 00:27 in glitchtutorialstutter

Stutter effects grab a small segment of live audio and play it back. It is a popular effect in electronic music, independently invented and developed in various ways by audio plugin developers. Here's how to do it in SuperCollider.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Source audio: simple sweep
{ Pulse.ar(XLine.kr(100, 1000, 5)) * 0.1!2 }.play;

// All you need is a varying delay.
// In this example, an 0.2s delay is switched on every other 0.2s. So every 0.2s of audio is repeated once.
(
{
    var snd = Pulse.ar(XLine.kr(100, 1000, 5));
    snd = DelayC.ar(snd, 0.2, LFPulse.ar((0.2 * 2).reciprocal) * 0.2);
    snd * 0.1!2;
}.play;
)

// More general version using Stepper instead of LFPulse. You can control the length of the repeat and the number of repeats.
(
{ |fragmentlength = 0.2, numrepeats = 3|
    var trig, reset, del, snd;
    snd = Pulse.ar(XLine.kr(100, 1000, 5));
    trig = Impulse.ar(fragmentlength.reciprocal);
    reset = Impulse.ar(0); // if we don't do this the stepper will start at 1...
    del = Stepper.ar(trig, reset, 0, numrepeats - 1) * fragmentlength;
    snd = DelayC.ar(snd, 10, del);
    snd * 0.1!2;
}.play(args: [\fragmentlength, 0.1, \numrepeats, 4]);
)

// With some enhancements, we can allow the reset counter to be out of sync.
(
{ |holdlength = 0.5, fragmentlength = 0.2|
    var reset, phase, fragment, del, snd;
    snd = Pulse.ar(XLine.kr(100, 1000, 5));

    reset = Impulse.ar(holdlength.reciprocal);
    phase = Sweep.ar(reset);
    // this is the easiest way to make an Impulse resettable? seriously?
    fragment = { |ph| (ph - Delay1.ar(ph)) < 0 + Impulse.ar(0) }.value(phase / fragmentlength % 1);
    del = Latch.ar(phase, fragment);
    snd = DelayC.ar(snd, 10, del);
    snd * 0.1!2;
}.play;
)

// Many stutter plugins let you play back the audio at a different rate.
// This is a little trickier. Speeding up 2x not as easy as adding a Sweep.ar(fragment) because otherwise you get negative delays.
// So you have to add in an extra delay equal to fragmentlength.
(
{ |holdlength = 0.5, fragmentlength = 0.2, rate = 1.5|
    var reset, phase, fragment, del, snd;
    snd = Pulse.ar(XLine.kr(100, 1000, 5));
    reset = Impulse.ar(holdlength.reciprocal);
    phase = Sweep.ar(reset);
    fragment = { |ph| (ph - Delay1.ar(ph)) < 0 + Impulse.ar(0) }.value(phase / fragmentlength % 1);
    del = Latch.ar(phase, fragment) + ((fragmentlength - Sweep.ar(fragment)) * (rate - 1));
    snd = DelayC.ar(snd, 10, del);
    snd * 0.1!2;
}.play;
)

(
~stutter = { |snd, reset, fragmentlength, rate = 1.0, maxdelay = 10|
    var phase, fragment, del;
    phase = Sweep.ar(reset);
    fragment = { |ph| (ph - Delay1.ar(ph)) < 0 + Impulse.ar(0) }.value(phase / fragmentlength % 1);
    del = Latch.ar(phase, fragment) + ((fragmentlength - Sweep.ar(fragment)) * (rate - 1));
    DelayC.ar(snd, maxdelay, del);
};
)

/*
// put this into your extensions dir to install as a pseudo-ugen
Stutter {
    *ar { |in, reset, length, rate = 1.0, maxdelay = 10|
        var phase, fragment, del;
        phase = Sweep.ar(reset);
        fragment = { |ph| (ph - Delay1.ar(ph)) < 0 + Impulse.ar(0) }.value(phase / length % 1);
        del = Latch.ar(phase, fragment) + ((length - Sweep.ar(fragment)) * (rate - 1));
        ^DelayC.ar(in, maxdelay, del);
    }
}
*/




// Next examples use this buffer
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");


// audio-rate stutter inspired by DestroyFX
(
{
    var snd, holdperiod, multiplier;
    snd = PlayBuf.ar(1, b, BufRateScale.kr(b), loop: 1);
    holdperiod = MouseY.kr(0.01, 1.0, 1);
    multiplier = MouseX.kr(1, 20);
    snd = ~stutter.(snd, Impulse.ar(holdperiod.reciprocal), holdperiod / multiplier);
    snd * 0.3!2;
}.play;
)

// feedback loop inspired by Glitchmachines
(
{
    var in, loop, out;
    in = PlayBuf.ar(1, b, BufRateScale.kr(b), loop: 1);
	out = (in!2*0.6) + DelayC.ar(LocalIn.ar(2), 0.3, [0.11, 0.13], 0.95);
    loop = out;
    loop = ~stutter.(loop, Impulse.kr([3.4, 5.5]), [0.1, 0.03], [0.8, 1.3]);
    loop = LPF.ar(loop, 5000);
	LocalOut.ar(loop.reverse);
    out * 0.3;
}.play;
)
)

// sequencing with Pmono
(
SynthDef(\stuttertest, {
    |out = 0, buf, t_reset = 0, fragmentlength = 0.1, amp = 0.1|
    var snd;
    snd = PlayBuf.ar(1, buf, BufRateScale.kr(buf), loop: 1);
    snd = ~stutter.(snd, t_reset, fragmentlength);
    Out.ar(out, snd * amp!2);
}).add;
)
(
Pmono(\stuttertest,
    \buf, b,
    \amp, 0.3,
    \reset, 1,
    \dur, 0.1,
    \fragmentlength, Pseq([0.01, 0.03, 0.07, 0.05, 0.06], inf)
).play;
)

// grab audio on onsets
// live performers like this because they can control the effect easily
(
{
    var snd, reset;
    snd = PlayBuf.ar(1, b, BufRateScale.kr(b), loop: 1);
    reset = Onsets.kr(FFT(LocalBuf(512), snd), 0.5);
    snd = ~stutter.(snd, reset, 0.05);
    snd = DelayC.ar(snd, 0.2, 0.2);
    snd!2 * 0.3;
}.play;
)

// "scrambler" -- randomly samples from recent audio
// even simpler than stutter, a favorite effect of mine
(
{
    var snd;
    snd = PlayBuf.ar(1, b, BufRateScale.kr(b), loop: 1);
    snd = DelayC.ar(snd, 1.0, LFNoise0.ar(13).range(0.0, 1.0));
    snd!2 * 0.3;
}.play;
)

/*
Some other options to try out:
Breakcore ugen in sc3-plugins
BBCut quark (see CutStream* classes for real-time stutter)
*/
raw 5182 chars (focus & ctrl+a+c to copy)
comments
alln4tural user 17 Feb'16 03:46

cool, thanks!

grirgz user 16 Nov'17 19:41

How I missed this ? This is wonderful! I struggled for hours with RecordBuf and the solution is so simple with delays :p thank you