如何在SuperCollider的Pbind中访问Buffer数组的当前Buffer信息?
问题描述
加载了一组包含音频采样的Buffer数组,通过Pbind随机将这些Buffer传递给Synth播放,希望把Pbind的\dur参数设置为当前播放Buffer的时长,但无法在Pbind内部访问当前Buffer的numFrames、sampleRate等属性,尝试过Pkey、Pfset、Plambda均未成功。相关代码如下:
// Synth定义 SynthDef(\player, { /* play a file from a buffer out: the output channel bufnum: the buffer to play */ arg out=0, bufnum; Out.ar( out, PlayBuf.ar(1, bufnum, BufRateScale.kr(bufnum), doneAction: Done.freeSelf)) ! 2 ) }).add; // Buffer数组加载 path = PathName.new("/path/to/files"); bufferArray = Array.new(100); path.filesDo({ arg file; bufferArray.add( Buffer.read(s, file.fullPath) ); }); // 问题中的Pbind代码 p = Pbind( \buffer, Prand(bufferArray, inf), \instrument, \player, \bufnum, Pkey(\buffer), \dur, (Pkey(\buffer.numFrames) / Pkey(\buffer.sampleRate)) )
解决方法
方法一:用Plambda直接获取Buffer属性
你之前的写法错误在于,Pkey只能引用事件中的键名,无法直接链式访问对象的属性(比如.numFrames)。可以用Plambda捕获当前事件中的\buffer对象,直接计算时长:
p = Pbind( \buffer, Prand(bufferArray, inf), \instrument, \player, \bufnum, Pkey(\buffer), \dur, Plambda { |event| // 从事件中取出当前Buffer对象,计算时长 event[\buffer].numFrames / event[\buffer].sampleRate } );
方法二:预计算时长数组(更高效)
如果不想每次播放时都计算时长,可以提前把所有Buffer的时长计算好,存在对应数组里,播放时直接随机选取:
// 加载Buffer时同时计算时长 path = PathName.new("/path/to/files"); bufferArray = []; durationArray = []; path.filesDo({ arg file; var buf = Buffer.read(s, file.fullPath); bufferArray.add(buf); // 预计算并存储时长 durationArray.add(buf.numFrames / buf.sampleRate); }); // 修改后的Pbind p = Pbind( \buffer, Prand(bufferArray, inf), \instrument, \player, \bufnum, Pkey(\buffer), // 对应选取预计算的时长 \dur, Prand(durationArray, inf) );
补充说明
两种方法都能实现需求:方法一适合Buffer可能动态变化的场景,方法二避免了实时计算的开销,更适合固定Buffer集合的场景。另外你的SynthDef已经设置了doneAction: Done.freeSelf,Synth会在播放完毕后自动释放,配合正确的\dur参数,就能实现每个采样播放完毕后再触发下一个的效果。
内容的提问来源于stack exchange,提问作者paulhector
相关产品推荐
相关产品推荐

