( ~dict = BmDspAlgs.getDict("spectral/fft_freeze.scd"); ~dict[\defaults] = ( attack: 0.01, release: 0.1, curve: 1 ); ~dict[\sustained] = true; ~dict[\useEnv] = true; ~dict2 = BmDspAlgs.getDict("spectral/fft_freeze_follow.scd"); ~dict.makeBufferProcessingNdef(\freeze1); ~dict.makeBufferProcessingNdef(\freeze2); ~dict2.makeBufferProcessingNdef(\freeze3); "instrumets loaded".postln; Ndef(\freeze1).set(\in, ~inBus.index); Ndef(\freeze2).set(\in, ~inBus.index); Ndef(\freeze3).set(\in, ~inBus.index); "inBus setted as NDefs input".postln; Ndef(\freeze1).put(10, \filter -> { |in| PitchShift.ar( in, 0.2, \shift.kr(2), 0.01, 0.01 ); }); Ndef(\freeze2).put(10, \filter -> { |in| PitchShift.ar( in, 0.2, \shift.kr(2), 0.01, 0.01 ); }); Ndef(\freeze1).set(\wet10, 0); Ndef(\freeze2).set(\wet10, 0); // Динамика: компрессор + нормалайзер + лимитер. // Сжимает громкое, поднимает тихое, не даёт пробить наушники. Ndef(\freeze1).put(20, \filter -> { |in| // Лёгкая компрессия: сжимаем только то, что выше порога (громкое). var comp = Compander.ar( in, in, thresh: \compThresh.kr(0.5), slopeBelow: 1.0, slopeAbove: \compSlope.kr(0.5), clampTime: \compClamp.kr(0.01), relaxTime: \compRelax.kr(0.1) ); // Нормалайзер: подтягивает тихий сигнал до норм. уровня (flattens dynamics). var norm = Normalizer.ar(comp, \normLevel.kr(0.5), \normDur.kr(0.05)); // Лимитер: жёсткий потолок от пробоя наушников. Limiter.ar(norm, \limLevel.kr(0.002), \limDur.kr(0.01)); }); Ndef(\freeze2).put(20, \filter -> { |in| // Лёгкая компрессия: сжимаем только то, что выше порога (громкое). var comp = Compander.ar( in, in, thresh: \compThresh.kr(0.5), slopeBelow: 1.0, slopeAbove: \compSlope.kr(0.5), clampTime: \compClamp.kr(0.01), relaxTime: \compRelax.kr(0.1) ); // Нормалайзер: подтягивает тихий сигнал до норм. уровня (flattens dynamics). var norm = Normalizer.ar(comp, \normLevel.kr(0.5), \normDur.kr(0.05)); // Лимитер: жёсткий потолок от пробоя наушников. Limiter.ar(norm, \limLevel.kr(0.002), \limDur.kr(0.01)); }); // Применяем specs из словарей к Ndef (нужно для GUI и маппинга контроллера). // TODO(bmSClib): автоматизировать — см. readme.org, секция TODO. ~dict[\specs].keysValuesDo { |k, v| Ndef(\freeze1).addSpec(k, v) }; ~dict[\specs].keysValuesDo { |k, v| Ndef(\freeze2).addSpec(k, v) }; ~dict2[\specs].keysValuesDo { |k, v| Ndef(\freeze3).addSpec(k, v) }; // Спек-параметры обёртки processSig (в dict их нет). [\freeze1, \freeze2, \freeze3].do { |n| Ndef(n).addSpec(\postAmp, [0, 1, \lin, 0, 1]); Ndef(n).addSpec(\pan, [-1, 1, \lin, 0, 0]); }; // Огибающая (useEnv) и питчшифтер есть только у freeze1/2. [\freeze1, \freeze2].do { |n| Ndef(n).addSpec(\envGate, [0, 1, \lin, 0, 0]); Ndef(n).addSpec(\attack, [0.001, 4, \exp, 0.001, 0.01]); Ndef(n).addSpec(\release, [0.001, 4, \exp, 0.001, 0.1]); Ndef(n).addSpec(\shift, [0.5, 2, \exp, 0.01, 2]); Ndef(n).addSpec(\wet10, [0, 1, \lin, 0, 0]); }; "FX added".postln; )