( name: 'grain_scatter', func: { | buf | var bufnum, rawSig, sig; // Кольцевой буфер (явно создаётся в скетче): RecordBuf пишет в // живой вход, WarpZ читает с растяжением и рандомизацией позиции. // Возвращает развёрнутый во времени сигнал, "разбросанный" по буферу. bufnum = \bufnum.kr(0); // Захват входа в кольцевой буфер. RecordBuf.ar() пишет в буфер // как побочный эффект; результат не используется. RecordBuf.ar( buf, bufnum, doneAction: 0 ); // WarpZ: чтение с растяжением и рандомизацией позиции rawSig = WarpZ.ar( numChannels: 2, bufnum: bufnum, freq: \warpFreq.kr(40), windowSize: \warpWindowSize.kr(0.15), position: \positionJitter.kr(0.3), posBase: \posBase.kr(0), overlaps: \overlaps.kr(4), windowRandRatio: \windowRandRatio.kr(0.2), freqMul: \freqMul.kr(1), interp: 2 ); // Duck на громкие моменты — общий паттерн для защиты от клиппинга sig = rawSig * (1 - \duckOnLoud.kr(0).clip(0, 1) * (Amplitude.kr(rawSig) > \duckThreshold.kr(0.95)).lag(0.05)); sig; }, inChannels: 2, outChannels: 2, requiresBuffer: true, specs: ( warpFreq: [1, 200, \exp, 1, 40], warpWindowSize: [0.01, 0.5, \lin, 0.01, 0.15], positionJitter: [0, 1, \lin, 0.01, 0.3], posBase: [0, 1, \lin, 0.01, 0.5], overlaps: [1, 16, \lin, 1, 4], windowRandRatio: [0, 1, \lin, 0.01, 0.2], freqMul: [0.25, 4, \exp, 0.01, 1], duckOnLoud: [0, 1, \lin, 0.01, 0.5], duckThreshold: [0, 1, \lin, 0.01, 0.95] ), )