From 5815a2258f5a6d82aa93830a7c97a74381c952be Mon Sep 17 00:00:00 2001 From: Ted Moore Date: Wed, 3 Nov 2021 17:04:04 +0000 Subject: [PATCH] include FluidPlotter and FluidWaveform --- .../HelpSource/Classes/FluidPlotter.schelp | 304 ++++++++++++++++++ .../HelpSource/Classes/FluidWaveform.schelp | 43 +++ 2 files changed, 347 insertions(+) create mode 100644 release-packaging/HelpSource/Classes/FluidPlotter.schelp create mode 100644 release-packaging/HelpSource/Classes/FluidWaveform.schelp diff --git a/release-packaging/HelpSource/Classes/FluidPlotter.schelp b/release-packaging/HelpSource/Classes/FluidPlotter.schelp new file mode 100644 index 0000000..a67eba3 --- /dev/null +++ b/release-packaging/HelpSource/Classes/FluidPlotter.schelp @@ -0,0 +1,304 @@ +TITLE:: FluidPlotter +summary:: A view for plotting data +categories:: Libraries>FluidCorpusManipulation +related:: Classes/FluidDataSet, Classes/FluidLabelSet, Classes/FluidKDTree, Classes/FluidKMeans + +DESCRIPTION:: +FluidPlotter is a viewer for plotting data. + + +CLASSMETHODS:: + +METHOD:: new +Creates a new instance of FluidPlotter + +ARGUMENT:: parent +A parent view to embed the FluidPlotter in. If no parent is passed, FluidPlotter will create a window for itself at the given bounds. + +ARGUMENT:: bounds +Where to show the FluidPlotter, either within the parent or on the screen (if no parent is passed). + +ARGUMENT:: dict +A link::Classes/Dictionary:: from a FluidDataSet dump method (or a similarly formatted Dictionary) that contains the data to be plotted. + +ARGUMENT:: mouseMoveAction +A function to execute on mouse down or mouse drag. This funtion is passed the strong::view:: (itself), strong::x position:: (scaled according to the xmin and xmax arguments of FluidPlotter), strong::y position:: (scaled according to the ymin and ymax arguments of FluidPlotter), strong::modifiers::, strong::button number::, and strong::click count::. The last two arguments are only useful on mouse down, not on mouse drag. + +ARGUMENT:: xmin +Minimum of the X range to display. Default is 0. + +ARGUMENT:: xmax +Maximum of the X range to display. Default is 1. + +ARGUMENT:: ymin +Minimum of the Y range to display. Default is 0. + +ARGUMENT:: ymax +Maximum of the Y range to display. Default is 1. + +returns:: +An instance of FluidPlotter + +INSTANCEMETHODS:: + +METHOD:: background +Set the background link::Classes/Color::. + +METHOD:: pointSize +Set the size of a specific point. + +ARGUMENT:: identifier +Which point to set the size of. + +ARGUMENT:: size +What size the point should be. This is a multiplier applied to the default point size which is 6 pixels. A point size of "2" will render a point with a diameter of 12 pixels. A point size of "0.5" will render a point with a diameter of 3 pixels. + +METHOD:: refresh +Refresh the link::Classes/UserView:: inside the FluidPlotter. + +METHOD:: xmin +Set xmin property and refresh the plotter. + +returns:: +xmin property. + +METHOD:: xmax +Set xmax property and refresh the plotter. + +METHOD:: ymin +Set ymin property and refresh the plotter. + +METHOD:: ymax +Set ymax property and refresh the plotter. + +METHOD:: addPoint +Manually add a single point to the FluidPlotter. Similar to the strong::addPoint:: method of link::Classes/FluidDataSet::, addPoint_ will not overwrite a point that already exists at the given identifier. Instead, a warning will be thrown. + +ARGUMENT:: identifier +The identifier associated with this point. + +ARGUMENT:: x +X position of the point. + +ARGUMENT:: y +Y position of the point. + +ARGUMENT:: color +What link::Classes/Color:: to make the point. If nothing is provided the point will default to link::Classes/Color::.black. + +ARGUMENT:: size +What size to make the point. This is a multiplier that modifies the default point size of 6 pixels. The default is 1. See strong::pointSize:: method above. + +METHOD:: setPoint +Similar to the strong::setPoint:: method of link::Classes/FluidDataSet::, setPoint_ will add a new point to the FluidPlotter. If a point already exists at the given identifier, it will be overwritten. + +ARGUMENT:: identifier +The identifier associated with this point. + +ARGUMENT:: x +X position of the point. + +ARGUMENT:: y +Y position of the point. + +ARGUMENT:: color +What link::Classes/Color:: to make the point. If nothing is provided the point will default to link::Classes/Color::.black. + +ARGUMENT:: size +What size to make the point. This is a multiplier that modifies the default point size of 6 pixels. The default is 1. See strong::pointSize:: method above. + +METHOD:: highlight +Increase the size of a point to make it more salient. Only one point can be "highlighted" at a time. To increase the size of multiple points, use method strong::pointSize::. + +ARGUMENT:: identifier +The identifier of the point to make salient. If nil is passes, not points' sizes will be changed. + +METHOD:: dict +Set a new link::Classes/Dictionary:: of points. Overwrites all previous points and Dictionaries. + +ARGUMENT:: d + +METHOD:: shape +Change the shape of the points, the options are \circle or \square. The default is \circle. + +ARGUMENT:: sh +(describe argument here) + +METHOD:: pointSizeScale +Scale all the points by a multiplier. See strong::pointSize_:: method above. The default is 1. + +ARGUMENT:: ps +(describe argument here) + +METHOD:: close +Close the plotter and/or its parent. + +METHOD:: pointColor +Change the link::Classes/Color:: of a point. + +ARGUMENT:: identifier +Identifier of the point to change the color of. + +ARGUMENT:: color +The link::Classes/Color:: to change the point to. + +METHOD:: parent + +returns:: The parent link::Classes/View:: of the FluidPlotter + +METHOD:: categories +Set categories to display as colors. + +ARGUMENT:: labelSetDict +This must be a link::Classes/Dictionary:: from a link::Classes/FluidLabelSet:: dump method, or a similarly formatted Dictionary. + +EXAMPLES:: + +code:: +( +// make some dummy data and plot it +~dummy_data = { + arg xmin = 20, xmax = 20000, ymin = -130, ymax = 0; + Dictionary.newFrom([ + "cols",2, + "data",Dictionary.newFrom(Array.fill(200,{ + arg i; + var return; + if((i % 2) == 0,{ + return = "example-%".format((i/2).asInteger); + },{ + return = [rrand(xmin,xmax),rrand(ymin,ymax)]; + }); + // return.postln; + return; + })) + ]); +}; + +Window.closeAll; +// self window +d = ~dummy_data.value; +// d.postln; +~fp = FluidPlotter(bounds:Rect(200,200,600,600),dict:d,mouseMoveAction:{ + arg view, x, y, modifiers; + [view, x, y, modifiers].dopostln; + "".postln; +},xmin:20,xmax:20000,ymin:-130,ymax:0); +) + +// click and drag on the plotter to report stuff in the mouseMoveAction callback function + +// change point size of just one point +~fp.pointSize_("example-5",10); + +// change it back +~fp.pointSize_("example-5",1); + +// change all points size bigger... +~fp.pointSizeScale_(2); + +// ...smaller... +~fp.pointSizeScale_(0.5); + +// ...back to normal +~fp.pointSizeScale_(1); + +( +// change 10 random points red +10.do({ + ~fp.pointColor_("example-%".format(rrand(0,99)),Color.red); +}); +) +// "highlight" a point (makes it a little bigger) +~fp.highlight_("example-95"); + +// a different one +~fp.highlight_("example-94"); + +// none +~fp.highlight_(nil); + +// put some different data in +~fp.dict_(~dummy_data.value); + +// change the ranges +( +~fp.ymin_(-140); +~fp.ymax_(10); +~fp.xmin_(-200); +~fp.xmax_(21000); +) + +// change the point shapes +~fp.shape_(\square); + +// change back to circles +~fp.shape_(\circle); + +// change the color of just one point +~fp.pointColor_("example-7",Color.red); + +// change the background color +~fp.background_(Color.red) +~fp.background_(Color.white) + +// ==== perform KMeans on the data and colorize the categories ====== +( +s.waitForBoot{ + Routine{ + var labelset = FluidLabelSet(s); + var kmeans = FluidKMeans(s); + var ds = FluidDataSet(s); + + s.sync; + + ds.load(~fp.dict,{ + kmeans.fitPredict(ds,labelset,{ + labelset.dump({ + arg lsdict; + defer{~fp.categories_(lsdict)}; + "done".postln; + }); + }); + }); + }.play; +} +) + +// close it or it's parent +~fp.close; + + +// a FluidPlotter inside a parent with parent +( +Window.closeAll; +d = Dictionary.newFrom([ + "cols",2, + "data",Dictionary.newFrom(Array.fill(200,{ + arg i; + var return; + if((i%2) == 0,{ + return = "example-%".format((i/2).asInteger); + },{ + return = [exprand(20,20000),rrand(-130,0)]; + }); + return; + })) +]); +w = Window("test",Rect(50,50,800,600)).front; +~fp = FluidPlotter(w,Rect(50,50,400,400),dict:d,mouseMoveAction:{ + arg view, x, y, modifiers; + [view, x, y, modifiers].dopostln; + "".postln; +},xmin:20,xmax:20000,ymin:-130,ymax:0); +) + +// you can make an empty one and then set the dict later +( +Window.closeAll; +~fp = FluidPlotter(bounds:Rect(100,100,500,500)) +) + +// now set data +~fp.dict_(~dummy_data.(0.01,1,0.0,1.0).postln); +:: diff --git a/release-packaging/HelpSource/Classes/FluidWaveform.schelp b/release-packaging/HelpSource/Classes/FluidWaveform.schelp new file mode 100644 index 0000000..e3279cd --- /dev/null +++ b/release-packaging/HelpSource/Classes/FluidWaveform.schelp @@ -0,0 +1,43 @@ +TITLE:: FluidWaveform +summary:: Buffer waveform display with optional overlays +categories:: Libraries>FluidCorpusManipulation +related:: Classes/FluidPlotter, Classes/FluidBufNoveltySlide, Classes/FluidBufOnsetSlice, Classes/FluidBufAmpSlice + +DESCRIPTION:: +FluidWaveform plots a buffer with optional overlays such as slices derived from a FluCoMa Slicer. + +CLASSMETHODS:: + +METHOD:: new +Create a new instance of FluidWaveform. + +ARGUMENT:: audio_buf +The audio buffer to plot. + +ARGUMENT:: slices_buf +A buffer of slice indices. This will very likely be in the form of a buffer output from a FluCoMa slicer object. Currently this buffer must be only one channel, therefore it will not work with the output of link::Classes/FluidBufAmpGate::. + +ARGUMENT:: bounds +A link::Classes/Rect:: of where to place the FluidWaveform. + +returns:: A new instance of FluidWaveform. + + +INSTANCEMETHODS:: + +EXAMPLES:: + +code:: + +// load a sound to slice +~drums = Buffer.read(s,File.realpath(FluidBufAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); + +// create a buffer to put indices into +~indices = Buffer(s); + +// do a slice analysis +FluidBufAmpSlice.process(s,~drums,indices:~indices,fastRampUp: 10,fastRampDown: 2205,slowRampUp: 4410,slowRampDown: 4410,onThreshold: 10,offThreshold: 5,floor: -40,minSliceLength: 4410,highPassFreq: 20); + +// plot the buffer with the indices overlayed +FluidWaveform(~drums,~indices,Rect(0,0,800,200)); +::