Conditionals - 'if'

Hi, guys

Wondering if it is possible to say in an ‘if’ statment, “when values goes from 0 to 1” do this, and “when value goes from 1 to 0” do that?

I have a midi CC fader, and I want to trigger a spesific sound when the fader goes from the lowest point and starts moving up, and an other sound for when it comes from the top and to 0.

Maybe I’m overlooking something really obvious…
Any clues greatly appreciated!
Thanks,
Lasse

That sounds like a crossfade. Something like…

\resultA.blend(\resultB, midicc.range(0, 1))

Look up the documentation on .blend if unsure.

I think you’ll want a variable that toggles when you hit either extreme something like

var downUp;
case { fader == 1 }{ downUp = \down }
{ fader == 0 }{ \downUp = \up}
{ true } { case { \downUp == \up} { do-my-up-thing }
           { \downUp == \down} {do-my-down-thing }
           { true } {do-whatever-I-do-before-reaching-either-end }
}

This isn’t a technique I see used often but, Routine’s can be used in many contexts as sort of “stateful” functions, since function invocation (e.g. calling object.value) for a Routine fetches it’s next value. This lets you do things like compare with the last value. What does this look like? For your MIDI controller example:

(

MIDIdef.cc(\control, 
	Routine({
		|midiMsg|
		var value, lastValue = 0; // you can start from e.g. midiMsg[0] as well
		
		loop {
			value = midiMsg[0];
			
			if (lastValue < value) {
				"Spawning a synth with control value: %".format(value).postln;
			};
			lastValue = value;
			
			// yield and fetch the next value. 
			// note that MIDIdef doesn't expect a responder function to return anything so you can yield anything you want here.
			midiMsg = nil.yield(); 
		}
	}),
	1
);

MIDIIn.doControlAction(1, 1, 1, 11);
MIDIIn.doControlAction(1, 1, 1, 21);
)

Thanks a lot! Your answer is a bit above my current level, but managed to tweak your example to almost do what I need:

(

MIDIdef.cc(\controlUp,
	Routine({
		|midiMsg|
		var value, lastValue = 0; 

		loop {
			value = midiMsg;

			if (lastValue < value && value == 1 ) {

				"Does my thing, when I moved upward to: 1".format(value).postln;
			//		Synth(\faderUpSound);
			};
			lastValue = value;
			
			value.postln;
			midiMsg = nil.yield();
		};


	});
	, 36
);
)

So that code does what I need - it triggers ‘something’ when I move my fader upwards, and it passes the value ‘1’.

But when I do the same for moving down I get:
ERROR: Message ‘&&’ not understood.

(

MIDIdef.cc(\controlDown,
	Routine({
		|midiMsg|
		var value, lastValue = 0; 

		loop {
			value = midiMsg;

			if (lastValue > value && value == 1 ) {

				"Does my thing, when I moved downward to: 1".format(value).postln;
			//		Synth(\faderDownSound);
			};
			lastValue = value;
			
			value.postln;
			midiMsg = nil.yield();
		};


	});
	, 36
);
)

However if I assign \controlDown to a different fader, it works - just not at the same time on the same fader…

Any ideas on how to fix that? Or I need a different approach to achieve this?

Thanks again.
L

I think you’re in the right track, you’ll have to put either side of the && in parentheses, SuperCollider’s order of operations for operators is always left to right, so this is trying to do a boolean operator when the right-hand-side value is a number.

Sorry, this solution is a little bit tricky! Hopefully it can be insightful, I recommended it because I struggled for years with how to represent this exact kind of - very conceptually simple! - operation before realizing I could do it this way with a Routine.

Maybe this helps? A Routine is essentially a function that can be paused and resumed. Rather than returning the value of the last statement, it returns to whoever called it whenever you call .yield on a value. The caller can then restart the function at that point by calling routine.value or routine.next. You can pass values OUT using yield, and pass them IN when you call value or next. The fact that you’re resuming it means you can keep track of things like the last value you received.

(
~routine = Routine({
  |input|
  "Passed '%' in from the outside".format(input).postln;
  input = 1.yield;
  "Passed '%' in from the outside".format(input).postln;
  input = 2.yield;
  "Passed '%' in from the outside".format(input).postln;
  3.yield;
  "okay, finished".postln;
});

~value = ~routine.next("abbie");
"Value yielded was %".format(~value).postln;
~value = ~routine.next("bishop");
"Value yielded was %".format(~value).postln;
~value = ~routine.next("cameron");
"Value yielded was %".format(~value).postln;
)

Thank you so much for your generous insights! I’m sure I can find a solution with this info. I’ll update the post when I’ve had time to sit down with it…But it will take me some time.