Midi integration with Multi Layer Perceptron with regression

Hi All,

Apologies for the rather noob question, but I’m trying to control the X and Y axis of the Slider2D object in the MLP regressor patch with two knobs on my MIDI controller (rather than my laptop mousepad). It works fine on the actual slider 2D GUI, but does not make any changes to the parameter modulations of the synth when in ‘predicting’ mode. I’m not sure what I’m missing here?

Thanks

1 Like

Hi @mick,

Can you post the code? I can probably eyeball it from there!

T

Sure. Here it is…

MIDIClient.init;
MIDIIn.connectAll;
MIDIFunc.trace(false);

(
MIDIdef.cc(\x1, {
arg val, num, chan, src;
[val, num].postln;
}).permanent_(true);
)

MIDIdef.freeAll;

(
Window.closeAll;
s.waitForBoot{
var synth, multislider, win, xyslider;
var xydata = FluidDataSet(s);
var paramsdata = FluidDataSet(s);
var xybuf = Buffer.alloc(s,2);
var paramsbuf = Buffer.alloc(s,10);
var counter = 0;
var predicting = false;
var ccx = 16;
var ccy = 17;

var mlp = FluidMLPRegressor(s,
	[7],
	activation:FluidMLPRegressor.sigmoid,
	outputActivation:FluidMLPRegressor.sigmoid,
	maxIter: 1000,
	learnRate:0.1,
	batchSize:1,
	validation:0
);

win = Window("ChaosSynth", Rect(10, 10, 840, 320)).front;

multislider = MultiSliderView(win,Rect(10, 10, 400, 300))
.elasticMode_(1)
.isFilled_(1)
.action_({
	arg ms;
	paramsbuf.setn(0,ms.value);
})
.value_(0.5.dup(10));




~s2d = Slider2D(win,Rect(420,10,300,300))
.action_{
	arg view;
	xybuf.setn(0,[view.x,view.y]);
	
	MIDIdef.cc(\x, {|n| {~s2d.x_(n/127)}.defer }, ccx);
	MIDIdef.cc(\y, {|n| {~s2d.y_(n/127)}.defer }, ccy);


	if(predicting){
		mlp.predictPoint(xybuf,paramsbuf,{
			paramsbuf.getn(0,10,{
				arg prediction;
				defer{
					multislider.value_(prediction);
				}
			});
		});
	};
};



Button(win,Rect(730,10,100,20))
.states_([["Add Points"]])
.action_{
	var id = "point-%".format(counter);
	xydata.addPoint(id,xybuf);
	paramsdata.addPoint(id,paramsbuf);
	counter = counter + 1;

	xydata.print;
	paramsdata.print;
};

Button(win,Rect(730,40,100,20))
.states_([["Save Data"]])
.action_{
	FileDialog({
		arg folder;
		folder.postln;
		xydata.write(folder+/+"xydata.json");
		paramsdata.write(folder+/+"paramsdata.json");
	},{},2,0,true);
};

Button(win,Rect(730,70,100,20))
.states_([["Load Data"]])
.action_{
	FileDialog({
		arg folder;
		xydata.read(folder+/+"xydata.json");
		paramsdata.read(folder+/+"paramsdata.json");
	},fileMode:2,acceptMode:0,stripResult:true);
};

Button(win,Rect(730,100,100,20))
.states_([["Train"]])
.action_{
	mlp.fit(xydata,paramsdata,{
		arg loss;
		loss.postln;
	});
};

Button(win,Rect(730,130,100,20))
.states_([["Save MLP"]])
.action_{
	Dialog.savePanel({
		arg path;
		if(PathName(path).extension != "json"){
			path = "%.json".format(path);
		};
		mlp.write(path);
	});
};

Button(win,Rect(730,160,100,20))
.states_([["Load MLP"]])
.action_{
	Dialog.openPanel({
		arg path;
		mlp.read(path);
	});
};

Button(win,Rect(730,190,100,20))
.states_([["Not Predicting"],["Predicting"]])
.action_{
	arg but;
	predicting = but.value.asBoolean;
};

s.sync;

synth = {
	var val = FluidBufToKr.kr(paramsbuf);
	var osc1, osc2, feed1, feed2, base1=69, base2=69, base3 = 130, loud1, loud2;
	#feed2, feed1 = LocalIn.ar(2);

	

	loud1 = FluidLoudness.kr(feed1,[\loudness],1,0,hopSize:64);
	loud2 = FluidLoudness.kr(feed2,[\loudness],1,0,hopSize:64);

	osc1 = SinOsc.ar((((feed1 * val[0]) +  val[1]) * base1).midicps,mul:(val[2] * 50).dbamp).atan;
	osc1 = MoogFF.ar(osc1,(base3-(val[3]*(loud2.clip(-120,0)+120))).lag(128/44100).midicps,val[4]*3.5);

	osc2 = SinOsc.ar((((feed2 * val[5]) +  val[6]) * base2).midicps,mul: (val[7] * 50).dbamp).atan;
	osc2 = MoogFF.ar(osc2,(base3-(val[8]*(loud1.clip(-120,0)+120))).lag(128/44100).midicps,val[9]*3.5);

	Out.ar(0,LeakDC.ar([osc1,osc2],mul:0.1));
	LocalOut.ar([osc1,osc2]);
}.play;

};
)

I haven’t tested it on my own machine, but these should come out of the Slider2D’s action method. Also you’ll want to use .activex_ and .activey_, or, .setXYActive to make sure that the Slider2D’s action function get’s called after the values are set. Let me know if that solves it!

T

Hi Ted,
That worked beautifully. Thanks for your generous time and help!

1 Like