关于你的最后一个子问题,
另外,有没有办法引用由事件创建的合成器?这样,当他们有sustain: inf争论时,我可以在以后释放他们。
Event是的,通过“索引”\id按键。这实际上返回了一个节点 ID 数组,因为一个事件\strum可以触发多个节点/合成器。此外,该\id值是nil事件未播放时的值。但是这种索引方法对于你想要的来说是相当不必要的,因为......
您可以通过以 结束Event早期来结束(关联的)合成器release,就像Synth它本身一样。这基本上是关闭其内部合成器。(在您的示例中,此调用通过降低到 0release转换到由 生成的 ASR 信封的释放点。 )。当然,如果不打算在程序中立即释放它(这不会产生带有门控包络的声音),请使用变量来保存对合成器和/或事件的“参考”。Linengate
基本上
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.playreturn 和EventStreamPlayer... 唉,制作正在播放的原型事件的私有副本并播放该私有副本,调用者上下文无法访问该副本(除非您 hack EventStreamPlayer.prNext)。令人困惑的是,EventStreamPlayer有一个可访问的event变量,但这只是“原型”,而不是正在播放的私有复制事件......因此,即使在播放时,如果p是一个EventStreamPlayerthen的实例,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 (可能是错误,但可能是“设计使然”)。此外,如果你使用Pdefwhich extends Eventtype \phrase... 上面的技巧并不能全部工作,即\id从不按类型设置\phrase;也许您可以了解以某种方式生成的潜在子事件......我没有费心进一步调查。
SC 文档(在模式指南中)甚至在某一点上说
请记住,由模式制成的流不会暴露其内部结构。这意味着您不能直接调整效果合成器的参数,因为您无法找出它的节点 ID 是什么。
鉴于上述黑客攻击,这并不完全正确,但在某些情况下确实如此。