diff --git a/release-packaging/Examples/dataset/1-learning examples/8b-mlp-synth-control.scd b/release-packaging/Examples/dataset/1-learning examples/8b-mlp-synth-control.scd index 49a3d38..c756125 100644 --- a/release-packaging/Examples/dataset/1-learning examples/8b-mlp-synth-control.scd +++ b/release-packaging/Examples/dataset/1-learning examples/8b-mlp-synth-control.scd @@ -1,90 +1,101 @@ //1- make the gui then the synth below ( -var trained = 0, entering = 0; -var va = Array.fill(10,{0.5}); -var input = Buffer.alloc(s,2); -var output = Buffer.alloc(s,10); -var mlp = FluidMLPRegressor(s,[6],activation: 1,outputActivation: 1,maxIter: 1000,learnRate: 0.1,momentum: 0,batchSize: 1,validation: 0); -var entry = 0; +Window.closeAll; +s.waitForBoot{ + Task{ + var trained = 0, entering = 0; + var input_buffer = Buffer.alloc(s,2); + var output_buffer = Buffer.alloc(s,10); + var mlp = FluidMLPRegressor(s,[6],activation: 1,outputActivation: 1,maxIter: 1000,learnRate: 0.1,momentum: 0.9,batchSize: 1); + var entry_counter = 0; + var win, multislider, xyslider, synth, error_st, prediction_but, addPoints_but, train_but; + var item_width = 100; + var inData = FluidDataSet(s); + var outData = FluidDataSet(s); -~inData = FluidDataSet(s); -~outData = FluidDataSet(s); + win = Window("ChaosSynth", Rect(10, 10, 840, 320)).front; -w = Window("ChaosSynth", Rect(10, 10, 790, 320)).front; -a = MultiSliderView(w,Rect(10, 10, 400, 300)).elasticMode_(1).isFilled_(1); -a.value=va; -a.action = {arg q; - b.set(\val, q.value); - va = q.value;}; -f = Slider2D(w,Rect(420,10,300, 300)); -f.x = 0.5; -f.y = 0.5; -f.action = {arg x,y; //if trained, predict the point f.x f.y - if (entering == 1, { //if entering a point, add to the the database f.x f.y against the array va - input.setn(0, [f.x, f.y]); - output.setn(0, va); - ~inData.addPoint(entry.asSymbol,input); - ~outData.addPoint(entry.asSymbol,output); - entering = 0; - entry = entry + 1; - {d.value = 0;}.defer; - }, { //if not entering a point - if (trained == 1, { //if trained - input.setn(0, [f.x, f.y]); - mlp.predictPoint(input,output,{ - output.getn(0,10,{ - |x|va = x; b.set(\val, va); {a.value = va;}.defer;}); + multislider = MultiSliderView(win,Rect(10, 10, 400, 300)) + .elasticMode_(1) + .isFilled_(1) + .action_({ + arg ms; + // ms.value.postln; + synth.set(\val,ms.value); + output_buffer.setn(0,ms.value); + }) + .value_(0.5.dup(10)); + + xyslider = Slider2D(win,Rect(420,10,300, 300)) + .x_(0.5) + .y_(0.5) + .action_({ + arg sl; + + input_buffer.setn(0,[sl.x,sl.y]); + + if(prediction_but.value.asBoolean,{ + mlp.predictPoint(input_buffer,output_buffer,{ + output_buffer.getn(0,10,{ + arg output_values; + synth.set(\val, output_values); + { + multislider.value_(output_values) + }.defer; + }); + }); }); }); - }); -}; -c = Button(w, Rect(730,240,50, 20)).states_([["train", Color.red, Color.white], ["trained", Color.white, Color.grey]]).action_{ - mlp.fit(~inData,~outData,{|x| - trained = 1; - { - c.value = 1; - e.value = x.round(0.001).asString; - }.defer; - });//train the network -}; -d = Button(w, Rect(730,10,50, 20)).states_([["entry", Color.white, Color.grey], ["entry", Color.red, Color.white]]).action_{ - entering = 1; -}; -StaticText(w,Rect(732,260,50,20)).string_("Error:"); -e = TextField(w,Rect(730,280,50,20)).string_(0.asString); -StaticText(w,Rect(732,70,50,20)).string_("rate:"); -TextField(w,Rect(730,90,50,20)).string_(0.1.asString).action_{|in|mlp.learnRate = in.value.asFloat.postln;}; -StaticText(w,Rect(732,110,50,20)).string_("momentum:"); -TextField(w,Rect(730,130,50,20)).string_(0.0.asString).action_{|in|mlp.momentum = in.value.asFloat.postln;}; -StaticText(w,Rect(732,150,50,20)).string_("maxIter:"); -TextField(w,Rect(730,170,50,20)).string_(1000.asString).action_{|in| mlp.maxIter = in.value.asInteger.postln;}; -StaticText(w,Rect(732,190,50,20)).string_("validation:"); -TextField(w,Rect(730,210,50,20)).string_(0.0.asString).action_{|in|mlp.validation = in.value.asFloat.postln;}; -) + addPoints_but = Button(win, Rect(730,10,item_width, 20)) + .states_([["add points", Color.white, Color.grey]]) + .action_({ + inData.addPoint(entry_counter.asSymbol,input_buffer); + outData.addPoint(entry_counter.asSymbol,output_buffer); + entry_counter = entry_counter + 1; + inData.print; + outData.print; + }); -//2- the synth -( -b = { - arg val = #[0,0,0,0,0,0,0,0,0,0]; - var osc1, osc2, feed1, feed2, base1=69, base2=69, base3 = 130; - #feed2,feed1 = LocalIn.ar(2); - osc1 = MoogFF.ar(SinOsc.ar((((feed1 * val[0]) + val[1]) * base1).midicps,mul: (val[2] * 50).dbamp).atan,(base3 - (val[3] * (FluidLoudness.kr(feed2, 1, 0, hopSize: 64)[0].clip(-120,0) + 120))).lag(128/44100).midicps, val[4] * 3.5); - osc2 = MoogFF.ar(SinOsc.ar((((feed2 * val[5]) + val[6]) * base2).midicps,mul: (val[7] * 50).dbamp).atan,(base3 - (val[8] * (FluidLoudness.kr(feed1, 1, 0, hopSize: 64)[0].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; -) + train_but = Button(win, Rect(730,240,item_width, 20)) + .states_([["train", Color.red, Color.white]]) + .action_({ + mlp.fit(inData,outData,{ + arg loss; + {error_st.string_("loss: %".format(loss.round(0.001)))}.defer; + }); + }); + prediction_but = Button(win, Rect(730,40,item_width, 20)) + .states_([["Not Predicting", Color.black, Color.white],["Predicting",Color.black,Color.white]]); + error_st = StaticText(win,Rect(732,260,item_width,20)).string_("Error:"); + StaticText(win,Rect(732,70,item_width,20)).string_("rate:"); + TextField(win,Rect(730,90,item_width,20)).string_(0.1.asString).action_{|in|mlp.learnRate = in.value.asFloat.postln;}; + StaticText(win,Rect(732,110,item_width,20)).string_("momentum:"); + TextField(win,Rect(730,130,item_width,20)).string_(0.9.asString).action_{|in|mlp.momentum = in.value.asFloat.postln;}; + StaticText(win,Rect(732,150,item_width,20)).string_("maxIter:"); + TextField(win,Rect(730,170,item_width,20)).string_(1000.asString).action_{|in| mlp.maxIter = in.value.asInteger.postln;}; -~inData.print; -~outData.print; + s.sync; + + //2- the synth + synth = { + arg val = #[0,0,0,0,0,0,0,0,0,0]; + var osc1, osc2, feed1, feed2, base1=69, base2=69, base3 = 130; + #feed2,feed1 = LocalIn.ar(2); + osc1 = MoogFF.ar(SinOsc.ar((((feed1 * val[0]) + val[1]) * base1).midicps,mul: (val[2] * 50).dbamp).atan,(base3 - (val[3] * (FluidLoudness.kr(feed2, 1, 0, hopSize: 64)[0].clip(-120,0) + 120))).lag(128/44100).midicps, val[4] * 3.5); + osc2 = MoogFF.ar(SinOsc.ar((((feed2 * val[5]) + val[6]) * base2).midicps,mul: (val[7] * 50).dbamp).atan,(base3 - (val[8] * (FluidLoudness.kr(feed1, 1, 0, hopSize: 64)[0].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; + }.play(AppClock); +}; +) ///////// //3 - play with the multislider -//4 - when you like a spot, click entry (become read) then a position in the 2D graph where this point should be +//4 - when you like a spot, move the 2d slider to a position that you want to represent that sound and click "add point" //5 - do that for a few points -//6 - click train +//6 - click train, keep clicking train until the loss is at or below 0.01 or so. feel free to adjust the learning rate, momentum, and max iter. //7 - the 2D graph controls the 10D -//8 - if you like a new sound and you want to update the graph, just click entry, then where it should be in the 2D, then retrain when you are happy