Set Timeout

Timeout

hello all!

the following code works so far, though it might not be the most elegant one.

~play = Routine{

~bufnum = Pseq([0, Pseq((1…8).scramble), 9], inf).asStream;

10.do{

~sendSwitchTrigger.set(0);

0.yield;

}.yieldAndReset(reset: true);

};

)

~perform = {~play.next}.defer(rrand(0.0, 2.0));

I would like to include a „timeout“:

if the Routine is not triggered for 10 sec, it should be reset to the beginning: I tried out „.idle(10), but I could not figure out, where to put it.

thanks for any suggestions!

best

Rainer

Hi,

Note that the code in your message isn’t formatted as code (so it’s lost indentation, for one thing).

The tricky thing about a timeout is that it has to be possible to cancel it, when the next trigger comes in. At one point a few years ago, it struck me that a Routine can be used like that.

if(~timeout.notNil) { ~timeout.stop };
~timeout = Routine {
    10.wait;
    ~play.reset;
}.play;

You can put that in where a trigger comes in. Each trigger will cancel the previous timeout, and schedule a new one.

hjh

hello jamshark!
many thanks for your reply!
sorry for the non formatied code, but I am blind, and navigating and handling the forum page is unfortunately very tricky for me.

the trrigger that comes in is a MIDIDef, that goes into a Trig.
best
Rainer

Oh, then I apologize – will try to remember that next time.

In that case, I would make a function that does both ~play.next and the timeout routine.

~go = {
    ~play.next;
    if(~timeout.notNil) { ~timeout.stop };
    ~timeout = Routine {
        10.wait;
        ~play.reset;
    }.play;
};

Then your MIDIdef can call this function. (The basic idea here is that all the functionality can be accessed through code instructions, without MIDI or GUI, and the interface layer just uses these functions.)

hjh

hello jamshark!
no problem!
now I am aware of it and I will ask a sighted person to assist, if code is in my post.

great thanks for your detailled explanation!
best
Rainer

hello jamshark!
I am sorry again for the not formated code, but I put this answer directly via email.

here is my complete code:
it partially works, but the „play“ routine is not reset, and the .defer and timeout settings are ignored, when playing it with a sustain pedal.
I guess, the MIDIdef comes in in a wrong place?

(
~numSpeakers = 2; // sets the number of available speakers (currently 2, will finally be set to 4)

s.options.numOutputBusChannels = ~numSpeakers; // sets accordingly the number of output channels

s.options.memSize= 1000000000;
s.boot;
)
(
Buffer.freeAll;

~pS = PathName(thisProcess.nowExecutingPath).parentPath ++ “projectSamples”;
~samples = ();

s.waitForBoot(~samples = PathName(~pS).files.collect({|n| Buffer.readChannel(s, n.fullPath, 0, -1, [0])}), limit: 100);
)

~samples.at(0).play;

(
SynthDef(\player, {
var env, sig;

env = Env.asr(
0.01, 1.0, 0.01, -4
).ar(2, [gate.kr](http://gate.kr)(1));

sig = PlayBuf.ar(
1, [bufnum.kr](http://bufnum.kr)(0), [pbRate.kr](http://pbRate.kr)(1), loop: 0
);

sig = sig * env;
sig = sig * [amp.kr](http://amp.kr)(1.0);

OffsetOut.ar([out.kr](http://out.kr)(0), sig)

}).add;
)

~testPlayer = Synth(\player, [\amp, 1]);

~testPlayer.set(\gate, 0);

(
~t1 = TempoClock(60 / 60).permanent_(true);

~bufnum = Pseq([0, Pseq((1…8).scramble, 1), 9], 1).asStream;
~speakerSeq = Pxrand((0…(~numSpeakers - 1)), inf).asStream;

~previousPlayer = nil;
~sendSwitchTrigger = {
~previousPlayer !? {|p| p.set(\gate, 0) };
~previousPlayer = Synth(\player, [\bufnum, ~bufnum.next, \out, ~speakerSeq.next]);
};
)

(
MIDIIn.connectAll;
MIDIdef.freeAll;

MIDIdef.cc(\ped1, {

val, ccNum, chan, src| val.postln;
~sendSwitchTrigger.set(\trig, val)
},
[ccNum: 64, chan: 0, src: “DOREMiDi MPC-20-13C4”]
).permanent_(true);
)
)

(
~play = Routine{

~bufnum = Pseq([0, Pseq((1…8).scramble), 9], inf).asStream; // deffines the sequence of audio samples to be played

~speakerSeq = Pxrand((0…(~numSpeakers - 1)), inf).asStream; // defines the sequence of speakers

10.do{
~previousPlayer;
0.yield;
}.yieldAndReset(reset: true);
};
)

~perform = {~play.next}.defer(rrand(0.0, 2.0));

(
~go = {
~play.next;
if(~timeout.notNil) { ~timeout.stop };
~timeout = Routine {
10.wait;
~play.reset;
}.play;
};
)

great thanks for any advise!best
Rainer

One way to format code (not sure if it works by email, worth a try) is to put three backticks at the start and end of the code block.

```
... my code...
```

Anyway, my initial read of your code is that it’s overcomplicated, so the first thing to do would be to simplify as much as possible. I see ~sendSwitchTrigger, ~play and ~go – presumably any and all of these are involved in responding to a MIDI event. How about one function to prepare the data (where the data could come from a routine) and play a synth?

Also, the reason why the MIDIFunc isn’t doing anything is because ~sendSwitchTrigger is a function. To activate the function, you should use the .value method, but you’re using .set (which is appropriate for a Synth). But if you want the timeout logic, then the MIDIFunc should be calling ~go also. (If you have a timeout function but never call it, then you’re not going to get timeout behavior.)

I’m sorry I can’t be more specific right now – it’s a bit unclear to me what you’re trying to do.

hjh

Had another look. I think this is closer – at least, it corrects several problems.

(
~numSpeakers = 2; // sets the number of available speakers (currently 2, will finally be set to 4)

s.options.numOutputBusChannels = ~numSpeakers; // sets accordingly the number of output channels

// btw, you asked for 1 TB of realtime memory in the server.
// I'm surprised your server booted at all.
// So I've reduced this number by a factor of 10000.
// Or you could try 300000 or 500000.
s.options.memSize = 100000;
s.boot;
)
(
Buffer.freeAll;

~pS = PathName(thisProcess.nowExecutingPath).parentPath ++ “projectSamples”;
~samples = ();

s.waitForBoot(~samples = PathName(~pS).files.collect({|n| Buffer.readChannel(s, n.fullPath, 0, -1, [0])}), limit: 100);
)

~samples.at(0).play;

(
SynthDef(\player, {
	var env, sig;
	
	env = Env.asr(
		0.01, 1.0, 0.01, -4
	).ar(2, \gate.kr(1));
	
	sig = PlayBuf.ar(
		1, \bufnum.kr(0), \pbRate.kr(1), loop: 0
	);
	
	sig = sig * env;
	sig = sig * \amp.kr(1.0);
	
	OffsetOut.ar(\out.kr(0), sig)
	
}).add;
)

~testPlayer = Synth(\player, [\amp, 1]);

~testPlayer.set(\gate, 0);

~initBufSpeakerStreams = {
	~bufnum = Pseq([0, Pseq((1..8).scramble), 9], inf).asStream; // deffines the sequence of audio samples to be played
	
	~speakerSeq = Pxrand((0..(~numSpeakers - 1)), inf).asStream; // defines the sequence of speakers
};

~playOneSynth = {
	~synth !? { |p| p.set(\gate, 0) };
	~synth = Synth(\player, [\bufnum, ~bufnum.next, \out, ~speakerSeq.next]);
};

~doTimeout = { |time = 10|
	if(~timeout.notNil) { ~timeout.stop };
	~timeout = Routine {
		time.wait;
		~initBufSpeakerStreams.();
	}.play(SystemClock);
};

~playSynth = {
	~playOneSynth.();
	~doTimeout.();
};


~t1 = TempoClock(60 / 60).permanent_(true);
~initBufSpeakerStreams.();	

(
// note: MIDIFunc srcID cannot be a string
// so we're going to search the sources array for a matching MIDIEndPoint
var src;

MIDIIn.connectAll;
MIDIdef.freeAll;

src = MIDIClient.sources.detect { |src|
	src.device.containsi("DOREMiDi MPC-20-13C4")
};

if(src.notNil) { src = src.uid };

MIDIdef.cc(\ped1, { |val, ccNum, chan, src|
	val.postln;
	~playSynth.();
}, ccNum: 64, chan: 0, srcID: src).permanent_(true);
)

To fix the unformatted code, btw, I had to use this regexp search to fix the synth args:

  • Search: \[([A-Za-z0-9_]+).kr\]\(http://[A-Za-z0-9_]+.kr\)\(([0-9.]+)\)
  • Replace: \\\1.kr(\2)

hjh

Oh, I see one other thing: the argument to waitForBoot should be a function. If the action is not wrapped in { }, then it will run immediately, and it’s no longer wait for boot.

s.waitForBoot({ ~samples = PathName(~pS).files.collect({|n| Buffer.readChannel(s, n.fullPath, 0, -1, [0])}) }, limit: 100);

hjh

1 Like

hello jamshark!
great thanks for all your efford and your advise!
and I am sorry for my late answer!

I think I now understand the structure of the code you provided: when evaluating the block beginning with „( // comment
var src;
…) an error shows up, posting that „var“ is not expected, but „end of file“.
did I overlook something?
best from Austria
Rainer

That block of code executes correctly for me, so I suspect the problem is that it’s not finding the boundaries of the region.

This could be due to a syntax error within the region, or (a little more difficult to troubleshoot) a syntax error in the same document earlier than the region.

hjh