{
   "labels" : [
      "convolution comb granular theory"
   ],
   "code" : "// fixed (unchanging) impulse response\r\n// cmd-. to stop\r\n\r\n(\r\ns.waitForBoot {\r\n\tvar c = Condition.new, cleanfunc = { CmdPeriod.remove(cleanfunc); b.free };\r\n\tfork {\r\n\t\tb = Buffer.alloc(s, 2048, 1);\r\n\t\tCmdPeriod.add(cleanfunc);\r\n\t\ts.sync;\r\n\t\ta = {\r\n\t\t\tRecordBuf.ar(BrownNoise.ar * EnvGen.ar(Env(#[0, 1, 0], #[0.5, 0.5], \\sin), timeScale: b.duration, doneAction: 2), b, loop: 0);\r\n\t\t\t0\r\n\t\t}.play;\r\n\t\tOSCpathResponder(s.addr, ['/n_end', a.nodeID], { |time, resp, msg|\r\n\t\t\tresp.remove;\r\n\t\t\tc.unhang;\r\n\t\t}).add;\r\n\t\tc.hang;\r\n\t\ta = {\r\n\t\t\tvar freq = MouseX.kr(150, 450, warp: 1, lag: 0.1);\r\n\t\t\tLeakDC.ar(Convolution2.ar(Impulse.ar(freq), b, framesize: b.numFrames) * -35.dbamp) ! 2;\r\n\t\t}.play;\r\n\t};\r\n};\r\n)\r\n\r\n\r\n\r\n// multiple impulse responses for timbre control\r\n(\r\ns.waitForBoot {\r\n\tvar c = Condition.new, cleanfunc = { CmdPeriod.remove(cleanfunc); b.free };\r\n\tfork {\r\n\t\tb = Buffer.allocConsecutive(3, s, 2048, 1);\r\n\t\tCmdPeriod.add(cleanfunc);\r\n\t\ts.sync;\r\n\t\ta = {\r\n\t\t\tvar sig = [BrownNoise.ar, PinkNoise.ar, WhiteNoise.ar];\r\n\t\t\tsig.do { |chan, i|\r\n\t\t\t\tRecordBuf.ar(chan * EnvGen.ar(Env(#[0, 1, 0], #[0.5, 0.5], \\sin), timeScale: b[i].duration, doneAction: 2), b[i], loop: 0);\r\n\t\t\t\t0\r\n\t\t\t};\r\n\t\t}.play;\r\n\t\tOSCpathResponder(s.addr, ['/n_end', a.nodeID], { |time, resp, msg|\r\n\t\t\tresp.remove;\r\n\t\t\tc.unhang;\r\n\t\t}).add;\r\n\t\tc.hang;\r\n\t\ta = {\r\n\t\t\tvar freq = MouseX.kr(150, 450, warp: 1, lag: 0.1),\r\n\t\t\t\tindex = MouseY.kr(0, 1.99, lag: 0.1),\r\n\t\t\t\tiWhole = index.trunc(2),\r\n\t\t\t\tiFrac = index - iWhole,\r\n\t\t\t\tiAdjust = iFrac >= 1.0,\r\n\t\t\t\ttrig = Impulse.ar(freq),\r\n\t\t\t\tconvolvers = b.collect { |buf, i|\r\n\t\t\t\t\tLeakDC.ar(Convolution2.ar(trig, buf, framesize: buf.numFrames))\r\n\t\t\t\t};\r\n\t\t\t(\r\n\t\t\t\tXFade2.ar(\r\n\t\t\t\t\tSelect.ar(iWhole + (2 * iAdjust), convolvers),\r\n\t\t\t\t\tSelect.ar(iWhole + 1, convolvers),\r\n\t\t\t\t\tiFrac.fold(0, 1) * 2 - 1\r\n\t\t\t\t) * -30.dbamp\r\n\t\t\t) ! 2;\r\n\t\t}.play;\r\n\t};\r\n};\r\n)",
   "id" : "1-2XJ",
   "is_private" : null,
   "author" : "jamshark70",
   "name" : "Abusing Convolution2 to make pitch",
   "description" : "Inspired by Formlet, which does something like formant synthesis by outputting short sinusoidal grains in response to impulses, I thought, what if we replace the sine grains with an arbitrary impulse response?\r\n\r\nYou could do that with TGrains, but as the pitch goes up, so does the number of overlapping grains and CPU use along with it. But, convolution of a chain of impulses should be the same as granular synthesis, if the grain contents are used as the convolution kernel (impulse response).\r\n\r\nThe first example does this with a buffer containing BrownNoise (shaped by a Hanning envelope). The second example adds timbre control by crossfading between three different Convolution2 results. To avoid clicks in the output when crossing buffer boundaries, I had to ensure that even-numbered buffers always go into XFade2's leftmost input and odd ones into the second input.\r\n\r\n(Note, the second example could be made more efficient/scalable by using just two Convolution2 units, and providing a trigger to the third input whenever its calculated buffer number changes. Exercise for the reader...)",
   "ancestor_list" : []
}
