From b687b5649da174f411fc2cebdff076a54b207fce Mon Sep 17 00:00:00 2001 From: Owen Green Date: Thu, 25 Jun 2020 16:38:55 +0100 Subject: [PATCH 1/2] Add KMeansClient RT support --- include/FluidSCWrapper.hpp | 8 ++ release-packaging/Classes/FluidKMeans.sc | 11 +-- .../Classes/FluidManipulationClient.sc | 84 +++++++++++++++++-- .../HelpSource/Classes/FluidKMeans.schelp | 33 +++++++- src/FluidManipulation/FluidManipulation.cpp | 2 +- 5 files changed, 121 insertions(+), 17 deletions(-) diff --git a/include/FluidSCWrapper.hpp b/include/FluidSCWrapper.hpp index 6d16c28..02c053b 100644 --- a/include/FluidSCWrapper.hpp +++ b/include/FluidSCWrapper.hpp @@ -92,6 +92,14 @@ struct IsModel>> using type = typename ClientWrapper::isModelObject; }; + +template +struct IsModel> +{ + using type = typename ClientWrapper::isModelObject; +}; + + template using IsModel_t = typename IsModel::type; diff --git a/release-packaging/Classes/FluidKMeans.sc b/release-packaging/Classes/FluidKMeans.sc index 5ebd7cb..dca6794 100644 --- a/release-packaging/Classes/FluidKMeans.sc +++ b/release-packaging/Classes/FluidKMeans.sc @@ -1,16 +1,7 @@ -FluidKMeans : FluidManipulationClient { +FluidKMeans : FluidDataClient { var <>k; - *new {|server| - var uid = UniqueID.next; - ^super.new(server,uid)!?{|inst|inst.init(uid);inst} - } - - init {|uid| - id = uid; - } - fit{|dataset,k, maxIter = 100, action| this.k = k; this.prSendMsg(\fit, diff --git a/release-packaging/Classes/FluidManipulationClient.sc b/release-packaging/Classes/FluidManipulationClient.sc index 541a87e..fd0315d 100644 --- a/release-packaging/Classes/FluidManipulationClient.sc +++ b/release-packaging/Classes/FluidManipulationClient.sc @@ -9,6 +9,7 @@ FluidProxyUgen : UGen { init { |pluginname...args| this.pluginname = pluginname; inputs = args++Done.none++0; + rate = inputs.rate; } name{ @@ -50,17 +51,23 @@ FluidManipulationClient { ^super.newCopyArgs(server ?? {Server.default}).baseinit(*args) } + makeDef { |defName...args| + ^SynthDef(defName,{ + var ugen = FluidProxyUgen.kr(this.class.name, *args); + this.ugen = ugen; + ugen + }); + } + + updateSynthControls {} + baseinit { |...args| var makeFirstSynth,synthMsg; id = UniqueID.next; postit = {|x| x.postln;}; keepAlive = true; defName = (this.class.name.asString ++ id).asSymbol; - def = SynthDef(defName,{ - var ugen = FluidProxyUgen.kr(this.class.name, *args); - this.ugen = ugen; - ugen - }); + def = this.makeDef(defName,*args); synth = Synth.basicNew(def.name, server); synthMsg = synth.newMsg(RootNode(server)); def.doSend(server,synthMsg); @@ -70,10 +77,12 @@ FluidManipulationClient { if(keepAlive){ synth = Synth(defName,target: RootNode(server)); synth.onFree{clock.sched(0,onSynthFree)}; + this.updateSynthControls; } }; CmdPeriod.add({synth = nil}); synth.onFree{clock.sched(0,onSynthFree)}; + this.updateSynthControls; } free{ @@ -118,6 +127,71 @@ FluidManipulationClient { } } +FluidDataClient : FluidManipulationClient { + + var ("FluidDataSetQuery",ft); makeSCWrapper("FluidLabelSet",ft); makeSCWrapper("FluidKDTree",ft); - makeSCWrapper("FluidKMeans",ft); + makeSCWrapper("FluidKMeans",ft); makeSCWrapper("FluidKNNClassifier",ft); makeSCWrapper("FluidKNNRegressor",ft); makeSCWrapper("FluidNormalize",ft); From 2d265783a0dacee657880dfe9d1f396fea468e8f Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Mon, 6 Jul 2020 14:57:17 +0100 Subject: [PATCH 2/2] working audio example of KR kmeans --- .../HelpSource/Classes/FluidKMeans.schelp | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidKMeans.schelp b/release-packaging/HelpSource/Classes/FluidKMeans.schelp index f635910..ef970a4 100644 --- a/release-packaging/HelpSource/Classes/FluidKMeans.schelp +++ b/release-packaging/HelpSource/Classes/FluidKMeans.schelp @@ -94,12 +94,14 @@ fork{ ~kmeans = FluidKMeans(s); // Fit into 4 clusters +( ~kmeans.fitPredict(~dataset,~clusters, 4, action: {|c| "Fitted.\n # Points in each cluster:".postln; c.do{|x,i| ("Cluster" + i + "->" + x.asInteger + "points").postln; } }); +) // Cols of kmeans should match dataset, size is the number of clusters ~kmeans.cols; @@ -120,6 +122,9 @@ fork{ } ) +//or faster by sorting the IDs +~clusters.dump{|x|~assignments = x.at("data").atAll(x.at("data").keys.asArray.sort{|a,b|a.asInteger < b.asInteger}).flatten.postln;} + //Visualise: we're hoping to see colours neatly mapped to quandrants... ( d = ((~points + 1) * 0.5).flatten(1).unlace; @@ -150,13 +155,13 @@ w.front; ~ob = Bus.control(s); //output bus can be kr ~inpPoint = Buffer.alloc(s,2); ~outPoint = Buffer.alloc(s,1); -//Set properties on FluidKMeans: -~kmeans.inBus_(~ib).outBus_(~ob).inBuffer_(~inpPoint).outBuffer_(~outPoint); ) //We make two Synths. One, before FluidKMeans, generates a random point and sends //a trigger to query. The second, after FluidKMeans, gives us the predicted cluster //triggering upadtes from the outBus ( +//Set properties on FluidKMeans: +~kmeans.inBus_(~ib).outBus_(~ob).inBuffer_(~inpPoint).outBuffer_(~outPoint); //pitching { var trig = Impulse.ar(10); @@ -170,6 +175,27 @@ w.front; { Poll.kr(In.kr(~ob),Latch.kr(BufRd.kr(1,~outPoint,0,interpolation:0),In.kr(~ob)),\cluster); }.play(~kmeans.synth,addAction:\addAfter); +) +// to sonify the output, here are random values alternating quadrant. +( +//Set properties on FluidKMeans: +~kmeans.inBus_(~ib).outBus_(~ob).inBuffer_(~inpPoint).outBuffer_(~outPoint); +//pitching +{ + var count,trig,point; + trig = Impulse.ar(MouseX.kr(0,1).exprange(0.5,1000)); + count = Stepper.ar(trig,0,0,3); + point = Latch.ar(WhiteNoise.ar([0.1,0.1],[count.div(2)-0.5,count.mod(2)-0.5]),trig); + BufWr.kr(point[0],~inpPoint,0);//annoying but triggered bufcompose or some other sort of entry here. (imagine having 20 mfccs here) + BufWr.kr(point[1],~inpPoint,1); + // Poll.kr(T2K.kr(trig),point,[\pointX,\pointY]); + Out.ar(~ib.index,[trig]); + trig*0.1; +}.play(~kmeans.synth,addAction:\addBefore); +//catching +{ + SinOsc.ar((Latch.kr(BufRd.kr(1,~outPoint,0,interpolation:0),In.kr(~ob)) + 69).midicps,mul: 0.1); +}.play(~kmeans.synth,addAction:\addAfter); ) ::