Why does it matter how I execute this code?

2019-07-25 01:27发布

I have built the following simple synth structure which creates a synth and routes its output through an effects unit:

b = Bus.audio(numChannels: 2);

SynthDef(
    "mySynth",
    {
        |freq, amp, gate = 1|
        var vol = 0.5;
        var audio = Pulse.ar(freq, 0.5);
        var env = EnvGen.kr(Env.perc, doneAction:2);
        audio = Pan2.ar(audio, MouseX.kr(-1, 1));
        Out.ar(b, audio * env);
    }
).add;


SynthDef(
    "effects",
    {
        var audio = In.ar(b, 2);
        audio = LPF.ar(audio, MouseY.kr(200, 1000));
                    //TODO: Implement some crazy, revolutionary effects
            Out.ar(0, audio);
    }
).add;

// **** Dividing line for executing the code ****

e = Synth(\effects);

p = Pbind(*[
    instrument: \mySynth,
    scale: #[0, 2, 4, 5, 7, 9, 11],
    degree: Pseq([3,        3,      9,      9,      2,      9,      9,      3,      5,      7], inf),
    dur:        Pseq([0.2,  0.2,    0.2,    0.1,    0.1,    0.2,    0.2,    0.2,    0.1,    0.1], inf),
    amp:        Pseq([1,        0.6,    0.9,    0.3,    0.4,    0.9,    0.6,    0.85,   0.3,    0.4], inf),
]);

p.play;

This only produces audible output when I execute the code in a particular way:

  • I can execute each block individually, in order, and I get audible output.
  • I can execute the first blocks up to the 'dividing line' comment, then the following blocks, and I get audible output.
  • If I execute all the code together, I don't get audible output.

I'm guessing there has to be some delay between declaring a SynthDef and then instantiate it using Synth(), while the server does set setup stuff. Can anyone shed any light?

3条回答
霸刀☆藐视天下
2楼-- · 2019-07-25 01:58

I usually get around this with the Server.sync() method. It pauses execution of the enclosing thread (e.g. a Routine) until all asynchronous server commands have been completed. This includes sending SynthDefs and allocating Buffers. You can pass a Condition argument to Server.sync() for more explicit control.

so for example, you can execute this block in one go:

s = Server.local;
s.boot;
s.doWhenBooted({
    Routine {
        SynthDef.new(\sine, {
            arg out=0, hz=220, dur=4.0;
            var snd, amp;
            snd = SinOsc.ar(hz);
            amp = EnvGen.ar(Env.linen(0.1, dur, 0.1), doneAction:2);
            Out.ar(out, (amp*snd).dup);
        }).send(s);
        s.sync; // waits here
        x = Synth.new(\sine);
    }.play;
});
查看更多
\"骚年 ilove
3楼-- · 2019-07-25 02:09

It is because you can't just "add" SynthDefs to the server and create an instance of said synth in the same execution. If you "play" the synths as they are executed then an instance of them gets added to the server so that when you call the Synth up for execution it will already be loaded. Working code is included below.

(
b = Bus.audio(numChannels: 2);

SynthDef(
    "mySynth",
    {
        |freq, amp, gate = 1|
        var vol = 0.5;
        var audio = Pulse.ar(freq, 0.5);
        var env = EnvGen.kr(Env.perc, doneAction:2);
        audio = Pan2.ar(audio, MouseX.kr(-1, 1));
        Out.ar(b, audio * env);
    }
).play;

SynthDef(
    "effects",
    {
        var audio = In.ar(b, 2);
        audio = LPF.ar(audio, MouseY.kr(200, 1000));
                    //TODO: Implement some crazy, revolutionary effects
            Out.ar(0, audio);
    }
).play;



// **** Dividing line for executing the code ****

e = Synth(\effects);

p = Pbind(*[
    instrument: \mySynth,
    scale: #[0, 2, 4, 5, 7, 9, 11],
    degree: Pseq([3,        3,      9,      9,      2,      9,      9,      3,      5,      7], inf),
    dur:        Pseq([0.2,  0.2,    0.2,    0.1,    0.1,    0.2,    0.2,    0.2,    0.1,    0.1], inf),
    amp:        Pseq([1,        0.6,    0.9,    0.3,    0.4,    0.9,    0.6,    0.85,   0.3,    0.4], inf),
]);

p.play;
)
查看更多
叼着烟拽天下
4楼-- · 2019-07-25 02:12

I'm sure you're right that it's to do with the delay between declaring the synthdef and it being ready.

I'm not really experienced enough with sclang to immediately tell you exactly how you should change your code (I generally use scsynth via OSC, only using sclang to write SynthDefs), but you should be able to do something with the optional completionMsg argument to SynthDef.add.

查看更多
登录 后发表回答