Tutorials on mapping a GUI to a controller?

Have been using SC awhile now but have never mapped a controller to a GUI and wondering if there are any tutorials.

Thnx

Eli Fieldsteel tutorials are always a good source of information, this one covers MIDI

1 Like

was thinking more along the lines of mapping a controller to a GUI if you have any recs

this is the code w/GUI if it helps:


(
~folder= "/Users/keenanmccracken/Desktop/insectopedia";  //edit this to point to a FOLDER with many soundfiles
~buffers.do{|x| x.free};
~buffers= (~folder+/+"*").pathMatch.collect{|x| Buffer.readChannel(s, x, channels:[0])};
)

//--load a sampler (a synth definition for playing a short grain of a buffer)
(
SynthDef(\avgrain, {|out= 0, buf, rate= 1, offset= 0, time= 0.1, amp= 0.1, pan= 0|
	var env= EnvGen.ar(Env.sine(time), doneAction:2);
	var src= PlayBuf.ar(1, buf, rate*BufRateScale.ir(buf), 1, offset*BufFrames.ir(buf), 1);
	OffsetOut.ar(out, Pan2.ar(src*env*amp, pan));
}).add;
)

//test
(
Pdef(\granulator, Pbind(\instrument, \avgrain,
	\buf, Pseq(~buffers, inf),
	\dur, 0.125,
	\time, 0.125,
	\offset, 0,
	\amp, 0.75,
)).play;
)

//main granulator
(
Pdef(\granulator, Pbind(\instrument, \avgrain,
	\buf, Pwrand(~buffers, Pdefn(\weights, 1.dup(~buffers.size).normalizeSum), inf),
	\dur, Pdefn(\dur, 0.125/8),
	\time, Pkey(\dur)*Pdefn(\overlap, 2.5),
	\rate, Pdefn(\rate, Pwhite(1, 1, inf)),
	\offset, Pdefn(\offset, Pwhite(0.25, 0.5, inf)),
	\amp, 0.5*Pdefn(\amp, Pwhite(1, 1, inf))*Pwrand([1, 0], Pdefn(\density, [1, 0]), inf),
	\pan, Pgauss(0, Pdefn(\pan, 0.25)),
)).play;
)

//gui interface
(
var win= Window("granulator", Rect(10, 10, 400, 600));
var mul;
win.layout= VLayout(
	StaticText().string_("buffer weights / mixer:"),
	mul= MultiSliderView().value_(Pdefn(\weights).source).elasticMode_(1)
	.action_({|v| Pdefn(\weights, v.value.normalizeSum)}),
	StaticText().string_("scan through buffers:"),
	Slider().orientation_(\horizontal)
	.action_({|v| mul.valueAction_(({|i| abs(i/(~buffers.size-1)-v.value).max(0.001)** -2}!~buffers.size).normalizeSum)}),
	StaticText().string_("duration:"),
	Slider().orientation_(\horizontal).value_(Pdefn(\dur).source*10)
	.action= {|v| Pdefn(\dur, v.value*0.1+0.001)},
	StaticText().string_("rate range:"),
	RangeSlider().orientation_(\horizontal).lo_(0.5).hi_(0.5)
	.action= {|v| Pdefn(\rate, Pwhite(v.lo*2, v.hi*2, inf))},
	StaticText().string_("overlap:"),
	Slider().orientation_(\horizontal).value_(Pdefn(\overlap).source*0.05)
	.action= {|v| Pdefn(\overlap, v.value*20)},
	StaticText().string_("offset range:"),
	RangeSlider().orientation_(\horizontal).lo_(0.25).hi_(0.5)
	.action= {|v| Pdefn(\offset, Pwhite(v.lo, v.hi, inf))},
	StaticText().string_("density:"),
	Slider().orientation_(\horizontal).value_(1)
	.action= {|v| Pdefn(\density, [v.value, 1-v.value])},
	StaticText().string_("amplitude range:"),
	RangeSlider().orientation_(\horizontal).lo_(1).hi_(1)
	.action= {|v| Pdefn(\amp, Pwhite(v.lo, v.hi, inf))},
	StaticText().string_("panning spread:"),
	Slider().orientation_(\horizontal).value_(0.25)
	.action= {|v| Pdefn(\pan, v.value)}
);
CmdPeriod.doOnce({win.close});
win.front;
)```

trying to map these to the sliders on a novation

Not sure if MIDI is still a feature in question. miSCellanous_lib’s VarGui has a MIDI learning feature (Ex. 10 of its help file), but of course it can also be used without.

1 Like

If you want to build it from scratch – there are two parts, GUI and MIDI.

You’ve pretty much laid out the GUI. One problem in your GUI code is that you don’t have variable references to your Slider() and RangeSlider() objects. If you want the MIDI controller to change these in the display, you will need to be able to access these objects.

MIDI – if you haven’t used MIDIFunc/MIDIdef before, then take a minute to try them and print out data from the controller.

Then you just need a bit of code to take the MIDI values and pop them into the GUI and Pdefn – that is, replace the “printout” code with “data --> GUI/Pdefn” code.

(I’m stepping through these because this is a common type of question – “I want to do something that involves multiple components” – if you try to do all of it at the same time, you will get confused. Breaking the problem down into smaller pieces is a really important approach.)

Based on this code structure, you could “cheat” by doing defer { theSlider.valueAction = ccvalue / 127 }. In my experience this isn’t the ideal dataflow, but it should be close enough to start with.

hjh

1 Like

This is an interesting topic.
I noticed there’s a SimpleController class for implementing a MVC pattern.
There’s also the addDependant / changed paradigm inbuilt or @scztt’s Connection quark.
If anybody has any experience connecting GUI / patterns or routines / MIDI it would be nice to share !

All the best

Geoffroy

There are two basic to control strategies for Patterns/EventStreamPlayer with a GUI: via environmental variables or via buses (well, you could invent intermediate controls, e.g. via dedicated control synths). IMO the most straight way (of per-event control) is the control of environmental variables. There are many examples with Patterns in the VarGui help files and also the Buffer Granulation Tutorial (the Pattern granulation examples). Control of Tasks and Routines works in the same way.

MVC is fine but before trying to implement it, consider if you really need it. After all, it comes along with a complication of implementation. Practically spoken, e.g.: in case you only have a GUI and no external device: do you really need to have your GUI react on some other change of state (programmatically)? Do want to control the GUI with an external device plus otherwise?

VarGui is not MVC, and in almost 15 years of usage I never missed that feature.

In special cases you could emulate MVC behaviour (VarGui help file example 6a).

2 Likes

thnx all

have miSC but haven’t looked into Var Gui yet so definitely will

In that case, start with “Tour 1: VarGui” in the “Introduction to miSCellaneous” help file. The VarGui class help file is a bit bloated.

Conceptually, using Pdefn is basically the same as using environment variables in this context – that’s one thing this thread’s original code example does right!

hjh