Displaying information on screen while changing parameters

Hi!
I just discovered SC yesterday, and I’m excited for its educational potential. I’ve been trying to find something to demonstrate to children (and adults) that pitch is rhythm, but speeding up a beat from 60bpm say, to 440 hertz, and hearing the transition from beat to pitch.

The first one I’ve been working with is this:

{ Impulse.ar([2*MouseX.kr(0, 150)], 0.0, 0.2) }.play;

What I would like is to have some indicator on screen of the number of impulses per minute and/or second. So when I have the mouse on the left of the screen it might a 1 for 1 beat per second, and as I move the mouse over, it will go up. Hopefully at 440 it will actually sound an A, though I still don’t know if it will because of the initial impulse sound. Actually, I could work that out easily enough now I think about it, but I think you get the point.

Is this possible? The same thing with harmony rhythms:

{ Impulse.ar([4*MouseX.kr(0, 50), 5*MouseX.kr(0, 50)], 0.0, 0.2) }.play;

Very excited about playing with this some more.

Surprised no one else took this up.

It’s certainly possible. MouseX is in the server and GUIs are in the language, so you have to transmit: SendReply and OSCFunc / OSCdef.

I also tweaked your sound source because impulses aren’t that great to listen to. You could load other audio into the buffer too.

s.boot;

b = Buffer.alloc(s, 4096, 1);

(
{
	var dur = BufDur.kr(b);
	var freq = XLine.ar(8000, 50, dur);
	var eg = EnvGen.ar(Env([0, 1, 0], [0.2, 0.8]), timeScale: dur, doneAction: 2);
	RecordBuf.ar(SinOsc.ar(freq) * eg, b, loop: 0);
	Silent.ar(1)
}.play;
)

(
a = {
	// for frequency, you really want exponential mapping
	var freq = MouseX.kr(1, 440, 1);
	var imp = Impulse.ar(freq, 0.0, 0.2);
	
	// for display
	SendReply.kr(Impulse.kr(10), '/freq', freq);
	
	// for sound
	(Convolution2.ar(imp, b, framesize: 4096) * 0.1).dup
}.play;
)

(
OSCdef(\freq, { |msg|
	defer { x.value = msg[3] };
}, '/freq', s.addr);

x = NumberBox(nil, Rect(800, 200, 150, 40)).front;
x.font_(Font.default.pixelSize_(36));

x.onClose = { OSCdef(\freq).free };
)

hjh

1 Like

We had a discussion about it the other day, tangentially.

It’s ok to not understand it at first glance. The implications of it will be obvious after a while.

Fundamentally, consider that there’s an actor that is interacting with a system. In this case you’re the actor, but generating events through the use of the mouse. But, what you’re really interested in is the number of impulses that will be played.

bus=Bus.control;
SynthDef(\mouse,{
arg bus;
 var sig=MouseX.kr(0,50);
Out.kr(bus,sig);
}).add;

SynthDef(\imp,{
 arg mouseinput;
var sig=In.kr(mouseinput);
sig= [ 4*sig,5*sig ];
sig=Impulse.ar(sig,0.0,0.2);
Out.ar(0,sig);
}).add;

a=Synth(\mouse,[\bus:bus]);
b=Synth(\imp,[\mouseinput:bus]);

// to read, 
bus.get(|x|, { x.postln;});
// Then have a task that updates a gui element
<< the gui creation code here >>

t=Task({
 inf.do({
 bus.get(|x|, { 
 x.postln;
 <<update gui part here>>.defer;
});


});
0.1.wait;
});
fork{
 t.start(AppClock);
}

Eventually, when there’s enough number of parameters for display, it’s easier to have a function that generates all the intermediate steps and chains everything together.

1 Like

Careful here though, the 0.1.wait needs to be one line above (inside the loop). Otherwise SC locks up.

Consistent indentation helps you spot this kind of thing more easily:

t=Task({
	inf.do({
		// oh wait... and you had |x| in the wrong place
		// fixing that...
		bus.get({ |x| 
			x.postln;
			<<update gui part here>>.defer;
		});
	});
	// this is outside of inf.do!
	// so it's an inf.don't
	// should move this before the immediately-preceding })
	0.1.wait;
});

hjh

You’re right, I was typing it out instead of copypasting.

Exciting stuff. Many thanks for your suggestions and help, I look forward to taking this code to computer next chance I get.

I thought (without any good reason) that a sinOsc might not work the same way, that it might not be a ‘bip’ or audible at slow tempos for example. Can’t wait to try it, it would be nice if it sounded a little more pleasant!

Should I be able to simply paste this code into SC, highlight all and cmd-enter?

When doing so I get this:
ERROR: syntax error, unexpected ‘(’, expecting end of file
in interpreted text
line 14 char 1:

(
^
a = {

ERROR: Command line parse failed
→ nil

but when I validate the three sections separately, they run, and I get the buffer, synth sound, and GUI! Simultaneously as well. So it works, but I need to compile it piece by piece. Am I missing some basic programming knowledge, like enclosing it all in {}?

I’ll keep experimenting.

Not in that form… there’s a convention in SC that a block in () should be run by itself, without other blocks.

(
this
is
a
block
)

Discussed in the tutorial series, 02. First Steps | SuperCollider 3.12.2 Help

In this case I think you can just pull them all into one block. It isn’t always that simple though.

hjh

Brill. Thanks, I can go and do my homework. Many thanks.

School these days must be really awesome to have supercollider in their curriculum