Закончив свой учебный курс по программированию, я подумал, что вернусь к SuperCollider с новым взглядом.

Я знаю, что есть правильный способ выполнять гранулярный синтез (создание звуков из кусочков других звуков размером с зерно) в SC. Это не так, и я даже не уверен, что это гранулированный синтез, поскольку зерна, которые я использую, довольно большие, но вы можете отрегулировать размер своих гранул, если хотите, чтобы звук был более «гранулярным».

Сначала загружаем образец:

~sample = Buffer.read(s, "/Users/matthewhinea/supercollider/buffer_files/inspectorj__wind-chimes-a.wav");

Я использую бесплатный файл .wav колокольчиков, но вы можете использовать любой звуковой файл. Файлы продолжительностью более 6,3 минуты (при частоте дискретизации 44100 Гц) не будут индексироваться точно, но мы индексируем их на случайные кадры, поэтому это не имеет особого значения.

Затем мы должны определить SynthDef, который будет воспроизводить файл.

(
  SynthDef(\playSample, {
    var outBus = 0;
    var susLevel = 0.6;
    var releaseTime = LFNoise0.kr(40, 2, 0.2);
    var startPos = LFNoise2.kr(500, 1, 0.0) * ~sample.numFrames;
    var gate = Line.kr(1, 0, 0.005);
    var amp = Linen.kr(gate, 0.01, susLevel, releaseTime, 2);
    var playBuf = PlayBuf.ar(2, ~sample, 1, 1, startPos: startPos, doneAction: 2);
    Out.ar(outBus, playBuf * amp);
    }).add
  )

Здесь важны releaseTime и startPos. Мы хотим индексировать файл в случайном кадре. Если бы мы просто использовали 1.0.rand, у нас было бы одно случайное число для всего определения, и каждый экземпляр синтезатора начинался бы с одного и того же кадра в файле. Передача UGen функции, которая ожидает значение, - это нормально; SuperCollider просто выбирает значение UGen. Та же самая логика применима к releaseTime.

Наш гейт - это простая линия, которая сразу же падает до 0, а наша амплитуда - это простая огибающая Linen, которая принимает нашу функцию releaseTime и doneAction «2», так что каждый экземпляр синтезатора исчезает после воспроизведения зерна.

Осталось только определить шаблон.

(
d = Pxrand(
  [10, 20, 30, 50, 80, 90, 120, 140, 150, 180, 200]/1000, inf).asStream;
t = Task({
 loop({
  x = Synth(\playSample);
    d.value.wait;
 });
});
t.start;
)

Здесь «d» - время ожидания в миллисекундах, а «t» - цикл, который создает экземпляр зерна, ждет несколько миллисекунд, а затем создает экземпляр другого зерна.