Что касается вашего последнего подвопроса,
Кроме того, есть ли способ ссылаться на синтезаторы, созданные событием? Так что, когда у них будет sustain: inf
в качестве аргумента, я смогу освободить их позже.
Да, "индексируя" ключ Event
по \id
. На самом деле это возвращает массив идентификаторов узлов, потому что событие с \strum
может запускать более одного узла/синтеза. Кроме того, значение \id
равно nil
, пока событие не воспроизводится. Но этот метод индексации совершенно не нужен для того, что вы хотите, потому что...
Вы можете закончить (связанный) синтезатор, закончив Event
раньше на release
, точно так же, как и для самого Synth
. То, что это делает, в основном отключает его внутренний синтезатор. (В вашем примере этот вызов release
переходит в точку освобождения конверта ASR, сгенерированного Linen
, путем понижения gate
до 0.). И, конечно же, используйте переменную, чтобы сохранить "ссылку" на синтезатор и/или событие, если не планируете сразу выпускать его в программе (что не даст звука с гейтированной огибающей).
В принципе
fork { var x = Synth(\testEvt); 2.wait; x.release }
делает то же самое, что
fork { var e = (instrument: \testEvt, sustain: inf).play; 2.wait; e.release }
за исключением того, что в последнем случае для выпуска есть один уровень косвенности. Первый пример также эквивалентен
fork { var x = Synth(\testEvt); 2.wait; x.set(\gate, 0); }
который выполняет работу release
явно. Event
также поддерживает set
и передает значение соответствующему элементу управления Synth
(если последний был правильно add
ed на сервере).
Теперь сложный метод, о котором вы спрашивали (получение идентификаторов узлов для события и отправка им сообщений), тоже возможен... хотя вряд ли это необходимо:
fork { var e = (instrument: \testEvt, sustain: inf).play; 2.wait;
e[\id].do({ arg n; s.sendMsg("/n_set", n, "gate", 0); }) }
Кстати, вы не можете использовать wait
вне Routine
, поэтому fork
было необходимо в приведенных выше примерах. В интерактивном режиме в редакторе вы, конечно, можете «подождать вручную», прежде чем вызывать release
либо на Synth
, либо на Event
.
В качестве тонкого момента в том, как работает гейтирование огибающей, оно фактически не начинает воспроизводиться (технически не начинает переход к конечной точке первого сегмента огибающей [атаки]), пока вы не установите гейт на 1. Т.е. вы можете отложить начало (конверта), как в:
fork { x = Synth(\testEvt, [\gate, 0]); 3.wait; x.set(\gate, 1); 2.wait; x.release }
Имейте в виду, что Event.play
по умолчанию не генерирует этот переход gate
от 0 до 1, т. е. вы не можете полагаться на него для срабатывания огибающей вашего синтезатора, если вы установите начальное значение gate
равным нулю в SynthDef
.
Кроме того, я предполагаю, что под «бесплатным» вы подразумеваете «прекратить играть», а не «освободить их память на сервере». Нет необходимости вручную освобождать эти (событийные) синтезаторы в последнем смысле, поскольку у них есть doneAction:2
в конверте, который сделает это за вас, как только они будут выпущены и завершится воспроизведение последнего сегмента конверта. Если вы каким-то образом хотите сразу убить синтезатор (как это делает Ctrl+.), вместо того, чтобы запускать его исчезновение, вы можете заменить сообщение, отправленное во внутренней функции «сложного» примера (выше), на s.sendMsg("/n_free", n)
. Или гораздо проще
fork { var e = (instrument: \testEvt, sustain: inf).play; 2.wait; e.free }
Кроме того, если вас интересует \strum
, вот пример:
e = (instrument: \testEvt, sustain: inf, strum: 1, out: #[0, 0]).play
Теперь e[\id]
представляет собой массив из двух узлов. Event
немного дерзок в том смысле, что он будет создавать несколько узлов только для массивов, переданных фактическим элементам управления Synth
, а не для случайных полей, поэтому «наигрывание» \freq
(или его предшественников, таких как \degree
и т. д.) создает несколько узлов только в том случае, если ваш SynthDesc
имеет элемент управления freq
.
Увы, "сложный" метод почти бесполезен, когда дело доходит до игры Pbind
s (паттернов). Это связано с тем, что Pbind.play
возвращает, а EventStreamPlayer
... увы, создает частную копию воспроизводимого события-прототипа и воспроизводит эту частную копию, которая недоступна для контекста вызывающей стороны (если только вы не взломаете EventStreamPlayer.prNext
). Как ни странно, EventStreamPlayer
имеет доступную переменную event
, но это только «прототип», а не воспроизводимое событие частной копии... Итак, если p
является экземпляром EventStreamPlayer
, то p.event[\id]
всегда равно нулю (или тому, что вы установили заранее) даже во время игры. Так как редко кто играет Events
индивидуально и гораздо чаще по шаблонам...
Просто в качестве сложного хакерского упражнения оказывается, что есть еще более запутанный способ доступа к идентификаторам узлов, которые запускает EventStreamPlayer
... Он основан на переопределении события по умолчанию play
, которое, к счастью, может быть расширено за пределы наследования класса, потому что значение по умолчанию удобно сохраняется в словаре класса...
(p = Pbind(\instrument, \testEvt, \sustain, Pseq([1, 2]), \play, {
arg tempo, srv;
var rv;
"playhack".postln;
rv = Event.parentEvents[\default][\play].value(tempo, srv);
~id.postln;
rv;
}).play)
Однако в целом шаблоны явно не предназначены для использования таким образом, то есть путем взлома «слоя ниже», чтобы получить идентификаторы узлов. В качестве «доказательства», хотя приведенное выше работает достаточно хорошо с Pbind
(который использует тип Event
по умолчанию \note
), он не работает надежно с Pmono
, который не устанавливает событие \id
на его первой ноте (тип события \monoNote
), а только на последующие заметки (которые генерируют другой тип события, \monoSet
). Pmono
хранит внутреннюю копию идентификатора узла, но она совершенно недоступна для первой мононоты; по какой-то причине он копирует его только в Event
s в последующих заметках (возможно, ошибка, но может быть «по замыслу»). Кроме того, если вы используете Pdef
, который расширяет Event
с типом \phrase
... приведенный выше хак не работает полностью, т.е. \id
никогда не устанавливается типом \phrase
; возможно, вы сможете добраться до основных подсобытий, сгенерированных каким-то образом... Я не удосужился исследовать дальше.
В документации SC (в руководстве по шаблонам) даже говорится в одном месте
Помните, что потоки, созданные из шаблонов, не раскрывают свои внутренности. Это означает, что вы не можете настроить параметры синтезатора эффектов напрямую, потому что у вас нет возможности узнать, какой у него идентификатор узла.
Это не совсем правильно, учитывая приведенный выше хак, но в некоторых контекстах это правда.
person
Fizz
schedule
21.02.2020