diff --git a/DSP/spectral/fft_freeze.scd b/DSP/spectral/fft_freeze.scd index 1c9de45..6a23444 100644 --- a/DSP/spectral/fft_freeze.scd +++ b/DSP/spectral/fft_freeze.scd @@ -3,46 +3,19 @@ name: 'fft_freeze', func: { | buf | - // Входной звук → FFT → freeze magnitude (PV_Freeze) + phase-jitter - // (PV_PhaseShift с шумом) → IFFT. - // - // FFT-буфер передаётся снаружи через \fftBufnum — это позволяет - // распределять буферы в скетче (s.options.numBuffers) и переиспользовать - // между перезапусками синта. - // - // Почему не кастомная пересборка chain из magnitude/phase: готовых - // PV_* UGen для неё нет, а PV_Chain не имеет метода .polar. - // UnpackFFT/PackFFT подходят для поканальной обработки, но не для - // uniform-операций вроде freeze или jitter. PV_Freeze + PV_PhaseShift - // дают ближайший готовый результат. - - var fftBuf = \fftBufnum.kr(0); - var chain = FFT( - fftBuf, + LocalBuf(2048), buf, - \hop.kr(0.25), - \wintype.kr(1) ); - // PV_Freeze принимает gate trigger: при freezeGate=1 удерживает - // magnitude, при 0 — пропускает как есть. var frozen = PV_Freeze(chain, \freezeGate.tr(0)); - - // Phase jitter: случайный сдвиг фазы всех бинов. Субъективно — - // "дыхание" frozen-спектра. var jittered = PV_PhaseShift(frozen, \phaseJitter.kr(0) * TRand.kr(0, 2pi)); - - var rawSig = IFFT(jittered, \wintype.kr(1)); - - // Duck на громкие моменты — общий паттерн для защиты от клиппинга - var sig = rawSig * (1 - \duckOnLoud.kr(0).clip(0, 1) * - (Amplitude.kr(rawSig) > \duckThreshold.kr(0.95)).lag(0.05)); + var sig = IFFT(jittered, \wintype.kr(1)); sig }, -inChannels: 2, -outChannels: 2, +inChannels: 1, +outChannels: 1, requiresBuffer: true, specs: ( phaseJitter: [0, 1, \lin, 0.01, 0.1],