|
|
|
@ -1,104 +0,0 @@
|
|
|
|
(
|
|
|
|
|
|
|
|
// Пример: spectral freeze + grain scatter.
|
|
|
|
|
|
|
|
// Концепция из README.org дуэта 24_09_2026 (концепция №1).
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Два независимых словаря:
|
|
|
|
|
|
|
|
// - fft_freeze — удержание magnitude, фазовый джиттер (PV_Freeze + PV_PhaseShift).
|
|
|
|
|
|
|
|
// - grain_scatter — WarpZ по кольцевому буферу, scatter позиции.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Оба словаря идут через makeBufferProcessingNdef — это стандартный
|
|
|
|
|
|
|
|
// путь для Fx/сэмплер-словарей в bmSClib: func получает audio-сигнал
|
|
|
|
|
|
|
|
// первым аргументом (| buf |), обёртка делает SynthDef.wrap(func, [buf])
|
|
|
|
|
|
|
|
// и кладёт результат в Ndef.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Входной звук подаётся через Bus — это стандартный паттерн для Fx,
|
|
|
|
|
|
|
|
// потому что makeBufferProcessingNdef передаёт \buf как OSC-параметр
|
|
|
|
|
|
|
|
// (control-rate число = номер bus), а не как UGen.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s.options.numBuffers = 1024; // FFT-буферы + ringbuffer для scatter
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s.waitForBoot({
|
|
|
|
|
|
|
|
// ---- Распределение буферов -------------------------------------
|
|
|
|
|
|
|
|
// FFT: явное распределение, как в шаблоне make-scd.el.
|
|
|
|
|
|
|
|
~fftBuf = Buffer.alloc(s, 1024, 2); // stereo FFT, 1024 сэмплов
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Кольцевой буфер для grain_scatter: 2 секунды, стерео.
|
|
|
|
|
|
|
|
~ringBuf = Buffer.alloc(s, s.sampleRate * 2.0, 2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---- Входной bus ------------------------------------------------
|
|
|
|
|
|
|
|
// В реальном концерте — звук от Letov или печатной машинки.
|
|
|
|
|
|
|
|
// Здесь — SoundIn.ar как stand-in, пишется в ~inBus отдельным
|
|
|
|
|
|
|
|
// синтом. Ndef читает этот bus по номеру через \buf.kr.
|
|
|
|
|
|
|
|
~inBus = Bus.audio(s, 2);
|
|
|
|
|
|
|
|
{ Out.ar(~inBus, SoundIn.ar([0, 1])) }.play;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---- Загрузка словарей ------------------------------------------
|
|
|
|
|
|
|
|
~freezeDict = BmDspAlgs.getDict("spectral/fft_freeze.scd");
|
|
|
|
|
|
|
|
~scatterDict = BmDspAlgs.getDict("spectral/grain_scatter.scd");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---- Режим 1: только freeze --------------------------------------
|
|
|
|
|
|
|
|
// makeBufferProcessingNdef(name, buf) — создаёт Ndef(\name) с
|
|
|
|
|
|
|
|
// func, обёрнутой через SynthDef.wrap(func, prependArgs: [buf]).
|
|
|
|
|
|
|
|
// buf — это audio-сигнал; здесь передаём номер bus.
|
|
|
|
|
|
|
|
~freezeDict.makeBufferProcessingNdef(\freezeOnly, ~inBus);
|
|
|
|
|
|
|
|
Ndef(\freezeOnly).set(\fftBufnum, ~fftBuf.bufnum);
|
|
|
|
|
|
|
|
Ndef(\freezeOnly).play;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Управление freeze-педалью: gate=1 триггерит freeze, gate=0
|
|
|
|
|
|
|
|
// отпускает. Удобно вешать на MIDI CC или OSC.
|
|
|
|
|
|
|
|
Ndef(\freezeOnly).addSpec(\freezeGate, [0, 1, \lin, 1, 0]);
|
|
|
|
|
|
|
|
Ndef(\freezeOnly).set(\freezeGate, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---- Режим 2: только scatter -------------------------------------
|
|
|
|
|
|
|
|
~scatterDict.makeBufferProcessingNdef(\scatterOnly, ~inBus);
|
|
|
|
|
|
|
|
Ndef(\scatterOnly).set(\bufnum, ~ringBuf.bufnum);
|
|
|
|
|
|
|
|
Ndef(\scatterOnly).play;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---- Режим 3: оба последовательно -------------------------------
|
|
|
|
|
|
|
|
// freeze → scatter: frozen-сигнал проходит через WarpZ.
|
|
|
|
|
|
|
|
// Ndef-цепочка: Ndef(\freezeOnly) пишет на свой bus, scatter
|
|
|
|
|
|
|
|
// читает с него.
|
|
|
|
|
|
|
|
~freezeBus = Bus.audio(s, 2);
|
|
|
|
|
|
|
|
Ndef(\freezeOnly)[0] = { Out.ar(~freezeBus, Ndef(\freezeOnly).bus.asMap) };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
~scatterDict.makeBufferProcessingNdef(\freezeAndScatter, ~freezeBus);
|
|
|
|
|
|
|
|
Ndef(\freezeAndScatter).set(\bufnum, ~ringBuf.bufnum);
|
|
|
|
|
|
|
|
Ndef(\freezeAndScatter).play;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---- Педали ------------------------------------------------------
|
|
|
|
|
|
|
|
// Управление через OSC / MIDI / HID. Ndef.set принимает числа,
|
|
|
|
|
|
|
|
// для live-управления — .map(\param, <CC>.kr).
|
|
|
|
|
|
|
|
Ndef(\freezeOnly).addSpec(\phaseJitter, [0, 1, \lin, 0.01, 0.1]);
|
|
|
|
|
|
|
|
Ndef(\freezeOnly).set(\phaseJitter, 0.1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ndef(\scatterOnly).addSpec(\positionJitter, [0, 1, \lin, 0.01, 0.3]);
|
|
|
|
|
|
|
|
Ndef(\scatterOnly).set(\positionJitter, 0.3);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---- Использование в перформансе -------------------------------------
|
|
|
|
|
|
|
|
// В живом концерте:
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// 1. freezeOnly: установить \freezeGate в 1, чтобы "заморозить"
|
|
|
|
|
|
|
|
// текущий вход. phaseJitter через педаль добавляет "дыхание"
|
|
|
|
|
|
|
|
// frozen-спектра.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// 2. На тихой паузе (Letov молчит) — включить freeze, и звук
|
|
|
|
|
|
|
|
// "дышит" сам по себе. Снять freeze — вернуться к реальному
|
|
|
|
|
|
|
|
// входу.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// 3. Когда Letov играет активно — scatterOnly поверх, с
|
|
|
|
|
|
|
|
// разбросом позиции через .map(\positionJitter, <CC>.kr).
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// 4. freezeAndScatter: сначала freeze, затем scatter по
|
|
|
|
|
|
|
|
// frozen-сигналу. Получается "зависший" звук, который
|
|
|
|
|
|
|
|
// разбивается на зёрна — главный спецэффект скетча.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// ---- Остановка -------------------------------------------------------
|
|
|
|
|
|
|
|
// Ndef(\freezeOnly).stop;
|
|
|
|
|
|
|
|
// Ndef(\scatterOnly).stop;
|
|
|
|
|
|
|
|
// Ndef(\freezeAndScatter).stop;
|
|
|
|
|
|
|
|
// ~fftBuf.free;
|
|
|
|
|
|
|
|
// ~ringBuf.free;
|
|
|
|
|
|
|
|
// ~inBus.free;
|
|
|
|
|
|
|
|
// ~freezeBus.free;
|
|
|
|
|
|
|
|
)
|
|
|
|
|