关于你的最后一个子问题,
另外,有没有办法引用由事件创建的合成器?这样,当他们有sustain: inf
争论时,我可以在以后释放他们。
Event
是的,通过“索引”\id
按键。这实际上返回了一个节点 ID 数组,因为一个事件\strum
可以触发多个节点/合成器。此外,该\id
值是nil
事件未播放时的值。但是这种索引方法对于你想要的来说是相当不必要的,因为......
您可以通过以 结束Event
早期来结束(关联的)合成器release
,就像Synth
它本身一样。这基本上是关闭其内部合成器。(在您的示例中,此调用通过降低到 0release
转换到由 生成的 ASR 信封的释放点。 )。当然,如果不打算在程序中立即释放它(这不会产生带有门控包络的声音),请使用变量来保存对合成器和/或事件的“参考”。Linen
gate
基本上
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
在服务器上正确编辑。)
现在您询问的复杂方法(检索事件的节点 ID 并向它们发送消息)也是可能的......虽然几乎没有必要:
fork { var e = (instrument: \testEvt, sustain: inf).play; 2.wait;
e[\id].do({ arg n; s.sendMsg("/n_set", n, "gate", 0); }) }
顺便说一句,您不能wait
在 a 之外使用Routine
,这就是fork
上面示例中需要的原因。交互式地,在编辑器中,您当然可以“手动等待” ,然后再调用release
或Synth
.Event
作为包络门控工作原理的一个微妙点,它实际上并没有开始播放(技术上开始过渡到第一个 [attack] 包络段的端点),直到您将门设置为 1。即您可以延迟(包络)开始如:
fork { x = Synth(\testEvt, [\gate, 0]); 3.wait; x.set(\gate, 1); 2.wait; x.release }
请注意,默认值Event.play
不会生成这种 0 到 1 的gate
过渡,即如果您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
return 和EventStreamPlayer
... 唉,制作正在播放的原型事件的私有副本并播放该私有副本,调用者上下文无法访问该副本(除非您 hack EventStreamPlayer.prNext
)。令人困惑的是,EventStreamPlayer
有一个可访问的event
变量,但这只是“原型”,而不是正在播放的私有复制事件......因此,即使在播放时,如果p
是一个EventStreamPlayer
then的实例,p.event[\id]
也总是为零(或您事先设置的任何值)。因为一个人很少单独演奏Events
,而更多时候是模式……
简单来说,黑客练习很困难,事实证明有一种更复杂的方式来访问EventStreamPlayer
触发的节点的 id... 这依赖于覆盖默认事件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)
然而,一般来说,模式显然不是为这种方式设计的,即通过破解“下面的一层”来获取节点 ID。Pbind
作为“证明”,虽然上面的内容与(使用默认Event
类型)一起工作得很好,\note
但它不能可靠地工作,Pmono
它不会\id
在其第一个音符(事件类型\monoNote
)上设置事件,但只能在后续音符上(生成一个不同的事件类型,\monoSet
)。Pmono
保留节点 ID 的内部副本,但在第一个单音音符上完全无法访问;出于某种原因,它仅将其复制到Event
后续注释中的 s (可能是错误,但可能是“设计使然”)。此外,如果你使用Pdef
which extends Event
type \phrase
... 上面的技巧并不能全部工作,即\id
从不按类型设置\phrase
;也许您可以了解以某种方式生成的潜在子事件......我没有费心进一步调查。
SC 文档(在模式指南中)甚至在某一点上说
请记住,由模式制成的流不会暴露其内部结构。这意味着您不能直接调整效果合成器的参数,因为您无法找出它的节点 ID 是什么。
鉴于上述黑客攻击,这并不完全正确,但在某些情况下确实如此。