Search code examples
functionoscsupercollider

In Supercollider I need to choose Ndefs to play and stop the previous from a list


Hi Iam using mindwave to control with OSC some Ndefs. I need to write a function that chooses from a list (eg [x, f]) the next and stops the previous. Also I need to be able to play only the first Ndef (eg x) and not the second (eg f) until I get the appropriate message (eg msg[3]) and at the same time to stop x. Here is my try which doesnt work as wanted:

(

OSCdef.new(
    \select,
    {
        arg msg, time, addr, port;
        [msg, time, addr, port].postln;


        if ((msg[3] > 200), {x.clear;} && {f.play;});





    },'/neurovals'
);



SynthDef.new(\Syn, { arg freq = 440,  amp = 1, sustain = 0.5;
    var sig, env, mod;
    env = EnvGen.kr(Env.linen(0.05, sustain, 0.5, 0.08), doneAction: 2);
    mod = Saw.ar(freq * 0.1) * LFNoise1.kr(2).range(10,800);
    sig = SinOsc.ar(freq + mod) * env;


    Out.ar(0, RLPF.ar(sig, freq, 1.7)).dup;

}).add;




x= Ndef(\blinkpat1, Pbind(
    \instrument, \Syn,
    \dur, 0.03,
    \freq, 440
));






OSCdef.new(
    \base,
    {
        arg msg, time, addr, port;
        [msg, time, addr, port].postln;



        if ((msg[1] == msg[1]),
            {x.set(\freq, msg[1].linlin(0, 100, 300, 1000);)});




    },'/neurovals'

);




SynthDef.new(\fmsyn, { arg freq = 440,  amp = 1, sustain = 1;
    var sig, env, mod;
    env = EnvGen.kr(Env.linen(0.05, sustain, 0.5, 0.08), doneAction: 2);
    mod = SinOsc.ar(freq * 0.5) * LFNoise1.kr(2).range(10,800);
    sig = SinOsc.ar(freq + mod) * env;


    Out.ar(0, RLPF.ar(sig, freq, 1.7)).dup;

}).add;




f = Ndef(\blinkpat2, Pbind(
    \instrument, \fmsyn,
    \freq, 440,
    \sustain, 2,
    \octave, 3,
    \amp, 0.4,
));





OSCdef.new(
    \base2,
    {
        arg msg, time, addr, port;
        [msg, time, addr, port].postln;

        if ((msg[1] == msg[1]),
            {f.set(\freq, msg[1].linlin(0, 100, 300, 1000);)});
        if ((msg[1] == msg[1]),
            {f.set(\sustain, msg[1].linlin(0, 100, 1, 2);)});





    },'/neurovals'

);
)

Solution

  • Firstly, this if statement:

    if ((msg[3] > 200), {x.clear;} && {f.play;});
    

    is strange - it's not clear trying to get with that, but it's unlikely that it's doing what you want. The && is a boolean operator, so the general expectation is the left and right sides are true/false. In your use, it's actually performing function composition on the left and right hand side functions, but that still isn't doing anything coherent, given your functions. I think what you probably intended is:

    if (msg[3] > 200) {
        x.clear;
        f.play;
    }
    

    ....which will clear x and play f.

    There are a number of ways you can do what I think you're trying to do. Here's one suggestion - Pdef's can be assigned to each other, and hot swapped during playback. This means, you can do:

    (  // set up \a, \b, and \player, and start playing \player
    Pdef(\a, Pbind(
        \dur, 1/4,
        \degree, 0,
    ));
    
    Pdef(\b, Pbind(
        \dur, 1/3,
        \degree, 2,
    ));
    
    \\ Start playing an empty Pdef to use later.   
    Pdef(\player).play;
    )  
    

    Then, you can set \player to one of \a or \b to transparently switch between them:

    // Assign Pdef(\a) to player, to start it playing
    Pdef(\player, Pdef(\a));
    
    // Assign Pdef(\b) to player, which starts \b and stops \a
    Pdef(\player, Pdef(\b));