为什么 EnvGen 在每次循环迭代时重新启动以及如何防止这种行为?
Why does EnvGen restart on every loop iteration and how to prevent this behavior?
如何在循环中使用 EnvGen,使其不会在循环的每次迭代中重新启动?
我需要它做什么:分段合成。我想要例如第一巴生和第二巴生之间 50 毫秒的渐变,然后 第二和第三巴生之间的 50 毫秒渐变,然后 第三和第四巴生之间的 50 毫秒渐变和依此类推,和我希望这个连接作为一个整体由包络调制。
不幸的是,EnvGen 似乎在播放连续的 Klang 对的循环的每次迭代中都从头开始重新启动。我想要一个 poiiiiinnnnnnnnnng,但无论我怎么尝试,我得到的都是 popopopopopopopopopo。
2019 编辑:
好的,既然没有人会回答 "how to achieve the goal" 的问题,我现在将这个问题降级为单纯的 "why doesn't this particular approach work",并更改标题。
在我粘贴一些代码之前,先解释一下:这是一个非常简化的示例。虽然我最初的愿望是用包络调制复杂的 piecewise-generated 声音,但这个简化的示例仅从 SinOsc 的输出中提取 "scissors" 100 毫秒的片段,只是为了人为地创建 "piecewise generation" 情况.
这个程序中发生的事情是 EnvGen 似乎在每次循环迭代时重新启动:包络从 t=0 重新启动。我希望得到一个 1 秒长的指数衰减声音,就像拨弦一样。由于包络在每次循环迭代开始时重新启动,我得到的是一系列 100 毫秒 "pings"。
如何防止这种情况发生?
代码如下:
//Exponential decay over 1 second
var envelope = {EnvGen.kr(Env.new([1,0.001],[1],curve: 'exp'), timeScale: 1, doneAction: 2)};
var myTask = Task({
//A simple tone
var oscillator = {SinOsc.ar(880,0,1);};
var scissor;
//Prepare a scissor that will cut 100ms of the oscillator signal
scissor = {EnvGen.kr(Env.new([1,0],[1],'hold'),timeScale: 0.1)};
10.do({
var scissored,modulated;
//Cut the signal with the scisor
scissored = oscillator*scissor;
//Try modulating with the envelope. The goal is to get a single 1s exponentially decaying ping.
modulated = {scissored*envelope};
//NASTY SURPRISE: envelope seems to restart here every iteration!!!
//How do I prevent this and allow the envelope to live its whole
//one-second life while the loop and the Task dance around it in 100ms steps?
modulated.play;
0.1.wait;
});
});
myTask.play;
(这个问题,我最初为此苦苦挣扎了几个月而没有成功,实际上让我搁置了我两年来学习 SuperCollider 的努力,现在我从我停下的地方继续学习。)
你在这里的工作方式有点不寻常。
使用 SuperCollider,您正在寻找的范式转变是将 SynthDef 创建为离散实体:
s.waitForBoot ({
b = Bus.new('control');
SynthDef(\scissors, {arg bus;
var env;
env = EnvGen.kr(Env.linen);
//EnvGen.kr(Env.new([1,0.001],[1],curve: 'exp'), timeScale: 1, doneAction: 2);
Out.kr(bus, env);
}).add;
SynthDef(\oscillator, {arg bus, out=0, freq=440, amp = 0.1;
var oscillator, scissored;
oscillator = SinOsc.ar(freq,0,1);
scissored = oscillator * In.kr(bus) * amp;
Out.ar(out, scissored);
}).add;
s.sync;
Task({
Synth(\scissors, [\bus, b]);
s.sync;
10.do({|i|
Synth(\oscillator, [\bus, b, \freq, 100 * (i+1)]);
0.1.wait;
});
}).play
});
我已经更改了更长的包络和音高变化,因此您可以听到所有振荡器启动的声音。
我所做的是定义了两个 SynthDef 和一个总线。
第一个 SynthDef 有一个包络,为了提高可听性,我加长了包络。它将那个信封的值写到总线上。这样,所有其他想要使用该共享信封的 SynthDef 都可以通过读取总线来获取它。
第二个 SynthDef 有一个 SinOsc。我们将其输出乘以总线输入。这使用共享包络来改变振幅。
这个“有效”,但如果你 运行 第二次,你会得到另一个令人讨厌的惊喜!振荡器 SynthDefs 还没有结束,你会再次听到它们。要解决这个问题,您需要给他们自己的信封或其他带有 doneAction 的东西。否则,他们将在每个单独的振荡器合成器上使用 forever.Putting 包络,这也是塑造每个振荡器开始的好方法。
您可能会在此示例中注意到的另一个新事物是 s.sync;
行。 SuperCollider 的一大特点是音频服务器和语言是独立的进程。该行确保服务器已赶上,因此我们不会在准备就绪之前尝试使用服务器端资源。这种 client/server 拆分也是为什么最好在使用它们之前定义 synthdefs 的原因。
我希望漫长的等待答案没有让您永久关闭。您可能会发现查看一些教程并以这种方式开始会很有帮助。
如何在循环中使用 EnvGen,使其不会在循环的每次迭代中重新启动?
我需要它做什么:分段合成。我想要例如第一巴生和第二巴生之间 50 毫秒的渐变,然后 第二和第三巴生之间的 50 毫秒渐变,然后 第三和第四巴生之间的 50 毫秒渐变和依此类推,和我希望这个连接作为一个整体由包络调制。
不幸的是,EnvGen 似乎在播放连续的 Klang 对的循环的每次迭代中都从头开始重新启动。我想要一个 poiiiiinnnnnnnnnng,但无论我怎么尝试,我得到的都是 popopopopopopopopopo。
2019 编辑:
好的,既然没有人会回答 "how to achieve the goal" 的问题,我现在将这个问题降级为单纯的 "why doesn't this particular approach work",并更改标题。
在我粘贴一些代码之前,先解释一下:这是一个非常简化的示例。虽然我最初的愿望是用包络调制复杂的 piecewise-generated 声音,但这个简化的示例仅从 SinOsc 的输出中提取 "scissors" 100 毫秒的片段,只是为了人为地创建 "piecewise generation" 情况.
这个程序中发生的事情是 EnvGen 似乎在每次循环迭代时重新启动:包络从 t=0 重新启动。我希望得到一个 1 秒长的指数衰减声音,就像拨弦一样。由于包络在每次循环迭代开始时重新启动,我得到的是一系列 100 毫秒 "pings"。
如何防止这种情况发生?
代码如下:
//Exponential decay over 1 second
var envelope = {EnvGen.kr(Env.new([1,0.001],[1],curve: 'exp'), timeScale: 1, doneAction: 2)};
var myTask = Task({
//A simple tone
var oscillator = {SinOsc.ar(880,0,1);};
var scissor;
//Prepare a scissor that will cut 100ms of the oscillator signal
scissor = {EnvGen.kr(Env.new([1,0],[1],'hold'),timeScale: 0.1)};
10.do({
var scissored,modulated;
//Cut the signal with the scisor
scissored = oscillator*scissor;
//Try modulating with the envelope. The goal is to get a single 1s exponentially decaying ping.
modulated = {scissored*envelope};
//NASTY SURPRISE: envelope seems to restart here every iteration!!!
//How do I prevent this and allow the envelope to live its whole
//one-second life while the loop and the Task dance around it in 100ms steps?
modulated.play;
0.1.wait;
});
});
myTask.play;
(这个问题,我最初为此苦苦挣扎了几个月而没有成功,实际上让我搁置了我两年来学习 SuperCollider 的努力,现在我从我停下的地方继续学习。)
你在这里的工作方式有点不寻常。
使用 SuperCollider,您正在寻找的范式转变是将 SynthDef 创建为离散实体:
s.waitForBoot ({
b = Bus.new('control');
SynthDef(\scissors, {arg bus;
var env;
env = EnvGen.kr(Env.linen);
//EnvGen.kr(Env.new([1,0.001],[1],curve: 'exp'), timeScale: 1, doneAction: 2);
Out.kr(bus, env);
}).add;
SynthDef(\oscillator, {arg bus, out=0, freq=440, amp = 0.1;
var oscillator, scissored;
oscillator = SinOsc.ar(freq,0,1);
scissored = oscillator * In.kr(bus) * amp;
Out.ar(out, scissored);
}).add;
s.sync;
Task({
Synth(\scissors, [\bus, b]);
s.sync;
10.do({|i|
Synth(\oscillator, [\bus, b, \freq, 100 * (i+1)]);
0.1.wait;
});
}).play
});
我已经更改了更长的包络和音高变化,因此您可以听到所有振荡器启动的声音。
我所做的是定义了两个 SynthDef 和一个总线。
第一个 SynthDef 有一个包络,为了提高可听性,我加长了包络。它将那个信封的值写到总线上。这样,所有其他想要使用该共享信封的 SynthDef 都可以通过读取总线来获取它。
第二个 SynthDef 有一个 SinOsc。我们将其输出乘以总线输入。这使用共享包络来改变振幅。
这个“有效”,但如果你 运行 第二次,你会得到另一个令人讨厌的惊喜!振荡器 SynthDefs 还没有结束,你会再次听到它们。要解决这个问题,您需要给他们自己的信封或其他带有 doneAction 的东西。否则,他们将在每个单独的振荡器合成器上使用 forever.Putting 包络,这也是塑造每个振荡器开始的好方法。
您可能会在此示例中注意到的另一个新事物是 s.sync;
行。 SuperCollider 的一大特点是音频服务器和语言是独立的进程。该行确保服务器已赶上,因此我们不会在准备就绪之前尝试使用服务器端资源。这种 client/server 拆分也是为什么最好在使用它们之前定义 synthdefs 的原因。
我希望漫长的等待答案没有让您永久关闭。您可能会发现查看一些教程并以这种方式开始会很有帮助。