From ce29afff89340c39307a9c234a49c52af8b79cad Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Sun, 21 Mar 2021 16:30:46 +0000 Subject: [PATCH 01/32] BufSelect(Every) : documentation in progress --- .../HelpSource/Classes/FluidBufSelect.schelp | 65 ++++++++++++++ .../Classes/FluidBufSelectEvery.schelp | 89 +++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 release-packaging/HelpSource/Classes/FluidBufSelect.schelp create mode 100644 release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp diff --git a/release-packaging/HelpSource/Classes/FluidBufSelect.schelp b/release-packaging/HelpSource/Classes/FluidBufSelect.schelp new file mode 100644 index 0000000..71c2b74 --- /dev/null +++ b/release-packaging/HelpSource/Classes/FluidBufSelect.schelp @@ -0,0 +1,65 @@ +TITLE:: FluidBufSelect +summary:: Cherry pick values from a buffer +categories:: FluidCorpusManipulation +related:: Classes/FluidBufSelectEvery + +DESCRIPTION:: +Pick sets of values from a buffer, described in terms of a list of frame indices and channel numbers. + +CLASSMETHODS:: + +private::new1 + +METHOD:: process, processBlocking +Run the process on the given sever, and perfrom code::action:: when done + +ARGUMENT:: server +The link::Classes/Server:: on which to run + +ARGUMENT:: source +The link::Classes/Buffer:: to select values from + +ARGUMENT:: destination +The link::Classes/Buffer:: to write the selected data to + +ARGUMENT:: indices +A 0-based list of frame indices to recover. Default is [-1], meaning all frames + +ARGUMENT:: channels +A 0-based list of channel numbers to recover. Default is [-1], meaning all frames + +ARGUMENT:: freeWhenDone +Free the server instance when processing complete. Default true + +ARGUMENT:: action +Runs when processing is complete + + +METHOD:: kr +Run as a control rate link::Classes/UGen:: + +ARGUMENT:: source +The link::Classes/Buffer:: to select values from + +ARGUMENT:: destination +The link::Classes/Buffer:: to write the selected data to + +ARGUMENT:: indices +A 0-based list of frame indices to recover. Default is [-1], meaning all frames + +ARGUMENT:: channels +A 0-based list of channel numbers to recover. Default is [-1], meaning all frames + +ARGUMENT:: trig +Trigger signal to defer / retrigger processing + +ARGUMENT:: blocking +The process will stay on the main server thread, or not if set to 0 + +returns:: an instance of the processor + +EXAMPLES:: + +code:: +//stuff here to get it +:: diff --git a/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp b/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp new file mode 100644 index 0000000..cef5f8e --- /dev/null +++ b/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp @@ -0,0 +1,89 @@ +TITLE:: FluidBufSelectEvery +summary:: Extract every N samples / channels from a buffer +categories:: FluidCorpusManipulation +related:: Classes/FluidBufSelect + +DESCRIPTION:: +Pick every N frames and / or channels from a buffer, described in terms of independent hop sizes for frames and channels + +CLASSMETHODS:: + +private::new1 + +METHOD:: process, processBlocking +Run the process on the given sever, and perfrom code::action:: when done + +ARGUMENT:: server +The link::Classes/Server:: on which to run + +ARGUMENT:: source +The link::Classes/Buffer:: to select values from + +ARGUMENT:: startFrame +The starting point (in samples) from which to copy in the source buffer. + +ARGUMENT:: numFrames +The duration (in samples) to copy from the source buffer. The default (-1) copies the full lenght of the buffer. + +ARGUMENT:: startChan +The first channel from which to copy in the source buffer. + +ARGUMENT:: numChans +The number of channels from which to copy in the source buffer. This parameter will wrap around the number of channels in the source buffer. The default (-1) copies all of the buffer's channel. + +ARGUMENT:: destination +The link::Classes/Buffer:: to write the selected data to + +ARGUMENT:: framehop +Take every `framehop` frames. Default = 1 = all frames (where 2 would be every other frame, etc.) + +ARGUMENT:: channelhop +Take every `channelhop` channels. Default = 1 = all channels (where 2 would be every other channel, etc.) + +ARGUMENT:: freeWhenDone +Free the server instance when processing complete. Default true + +ARGUMENT:: action +Runs when processing is complete + + +METHOD:: kr +Run as a control rate link::Classes/UGen:: + +ARGUMENT:: source +The link::Classes/Buffer:: to select values from + +ARGUMENT:: startFrame +The starting point (in samples) from which to copy in the source buffer. + +ARGUMENT:: numFrames +The duration (in samples) to copy from the source buffer. The default (-1) copies the full lenght of the buffer. + +ARGUMENT:: startChan +The first channel from which to copy in the source buffer. + +ARGUMENT:: numChans +The number of channels from which to copy in the source buffer. This parameter will wrap around the number of channels in the source buffer. The default (-1) copies all of the buffer's channel. + +ARGUMENT:: destination +The link::Classes/Buffer:: to write the selected data to + +ARGUMENT:: frameHop +Take every `framehop` frames. Default = 1 = all frames (where 2 would be every other frame, etc.) + +ARGUMENT:: channelHop +Take every `channelhop` channels. Default = 1 = all channels (where 2 would be every other channel, etc.) + +ARGUMENT:: trig +Trigger signal to defer / retrigger processing + +ARGUMENT:: blocking +The process will stay on the main server thread, or not if set to 0 + +returns:: an instance of the processor + +EXAMPLES:: + +code:: +//stuff here to get it +:: From 749b52666c5c83cddf3387637251b3cf61be700c Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Sun, 21 Mar 2021 17:46:24 +0000 Subject: [PATCH 02/32] BufSelect(Every) : remove ref to .kr in doc --- .../HelpSource/Classes/FluidBufSelect.schelp | 24 ----------- .../Classes/FluidBufSelectEvery.schelp | 40 +------------------ 2 files changed, 2 insertions(+), 62 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidBufSelect.schelp b/release-packaging/HelpSource/Classes/FluidBufSelect.schelp index 71c2b74..657dc8a 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSelect.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSelect.schelp @@ -34,30 +34,6 @@ Free the server instance when processing complete. Default true ARGUMENT:: action Runs when processing is complete - -METHOD:: kr -Run as a control rate link::Classes/UGen:: - -ARGUMENT:: source -The link::Classes/Buffer:: to select values from - -ARGUMENT:: destination -The link::Classes/Buffer:: to write the selected data to - -ARGUMENT:: indices -A 0-based list of frame indices to recover. Default is [-1], meaning all frames - -ARGUMENT:: channels -A 0-based list of channel numbers to recover. Default is [-1], meaning all frames - -ARGUMENT:: trig -Trigger signal to defer / retrigger processing - -ARGUMENT:: blocking -The process will stay on the main server thread, or not if set to 0 - -returns:: an instance of the processor - EXAMPLES:: code:: diff --git a/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp b/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp index cef5f8e..d48faae 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp @@ -34,10 +34,10 @@ The number of channels from which to copy in the source buffer. This parameter w ARGUMENT:: destination The link::Classes/Buffer:: to write the selected data to -ARGUMENT:: framehop +ARGUMENT:: frameHop Take every `framehop` frames. Default = 1 = all frames (where 2 would be every other frame, etc.) -ARGUMENT:: channelhop +ARGUMENT:: channelHop Take every `channelhop` channels. Default = 1 = all channels (where 2 would be every other channel, etc.) ARGUMENT:: freeWhenDone @@ -46,42 +46,6 @@ Free the server instance when processing complete. Default true ARGUMENT:: action Runs when processing is complete - -METHOD:: kr -Run as a control rate link::Classes/UGen:: - -ARGUMENT:: source -The link::Classes/Buffer:: to select values from - -ARGUMENT:: startFrame -The starting point (in samples) from which to copy in the source buffer. - -ARGUMENT:: numFrames -The duration (in samples) to copy from the source buffer. The default (-1) copies the full lenght of the buffer. - -ARGUMENT:: startChan -The first channel from which to copy in the source buffer. - -ARGUMENT:: numChans -The number of channels from which to copy in the source buffer. This parameter will wrap around the number of channels in the source buffer. The default (-1) copies all of the buffer's channel. - -ARGUMENT:: destination -The link::Classes/Buffer:: to write the selected data to - -ARGUMENT:: frameHop -Take every `framehop` frames. Default = 1 = all frames (where 2 would be every other frame, etc.) - -ARGUMENT:: channelHop -Take every `channelhop` channels. Default = 1 = all channels (where 2 would be every other channel, etc.) - -ARGUMENT:: trig -Trigger signal to defer / retrigger processing - -ARGUMENT:: blocking -The process will stay on the main server thread, or not if set to 0 - -returns:: an instance of the processor - EXAMPLES:: code:: From a94dabb313f4a6b55fa0291b206e7baad6d6d3ab Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Mon, 22 Mar 2021 10:23:03 +0000 Subject: [PATCH 03/32] bufselect(every): toy examples as demo in helpfiles --- .../HelpSource/Classes/FluidBufSelect.schelp | 25 +++++++++++++++-- .../Classes/FluidBufSelectEvery.schelp | 28 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidBufSelect.schelp b/release-packaging/HelpSource/Classes/FluidBufSelect.schelp index 657dc8a..e20a544 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSelect.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSelect.schelp @@ -35,7 +35,28 @@ ARGUMENT:: action Runs when processing is complete EXAMPLES:: - code:: -//stuff here to get it +//send a known collection where the value of each frame in each channel is encoded +//chan +b = Buffer.sendCollection(s,30.collect{|x| x.mod(6) + (x.div(6) * 0.1)},6) +//check the ranges (thus showing a plotter error...) +b.plot(separately: true).plotMode_(\points) +//you can also check the collection itself if in doubt +b.getToFloatArray(action: {|x|x.round(0.1).postln;}); + +//let's make a destination buffer +c = Buffer(s); + +//using default values, we copy everything: +FluidBufSelect.process(s,b,c,action: {c.query}); +c.getToFloatArray(action: {|x|x.round(0.1).postln;}); + +//more powerful copying, resizing the destination accordingly +FluidBufSelect.process(s,b,c, indices: [1,3], channels: [2,4], action: {c.query}); +c.getToFloatArray(action: {|x|x.round(0.1).postln;}); + +//observe the order can be anything, and -1 (default) passes everything in that dimension +FluidBufSelect.process(s,b,c, indices: [ -1 ] , channels: [3, 1, 4], action: {c.query}); +c.getToFloatArray(action: {|x|x.round(0.1).postln;}); :: + diff --git a/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp b/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp index d48faae..cb83c0e 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSelectEvery.schelp @@ -49,5 +49,29 @@ Runs when processing is complete EXAMPLES:: code:: -//stuff here to get it -:: +EXAMPLES:: +Didactic +code:: +//send a known collection where the value of each frame in each channel is encoded +//chan +b = Buffer.sendCollection(s,30.collect{|x| x.mod(6) + (x.div(6) * 0.1)},6) +//check the ranges (thus showing a plotter error...) +b.plot(separately: true).plotMode_(\points) +//you can also check the collection itself if in doubt +b.getToFloatArray(action: {|x|x.round(0.1).postln;}); + +//let's make a destination buffer +c = Buffer(s); + +//using default values, we copy everything: +FluidBufSelectEvery.process(s,b, destination: c, action: {c.query}); +c.getToFloatArray(action: {|x|x.round(0.1).postln;}); + +//more powerful copying, resizing the destination accordingly +FluidBufSelectEvery.process(s,b, destination: c, frameHop: 2, channelHop: 3, action: {c.query}); +c.getToFloatArray(action: {|x|x.round(0.1).postln;}); + +//source buffer boundaries still apply before the hopping selection +FluidBufSelectEvery.process(s,b, startFrame: 1, numFrames: 3, startChan: 2, numChans: 3, destination: c, frameHop: 1, channelHop: 2, action: {c.query}); +c.getToFloatArray(action: {|x|x.round(0.1).postln;}); +:::: From 25069e59f16f913eb29533de2b25b680d86d5916 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Mon, 22 Mar 2021 11:53:45 +0000 Subject: [PATCH 04/32] remove troubleshooting print --- release-packaging/Classes/FluidBufSelect.sc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/release-packaging/Classes/FluidBufSelect.sc b/release-packaging/Classes/FluidBufSelect.sc index a9cf200..ff0a9d7 100644 --- a/release-packaging/Classes/FluidBufSelect.sc +++ b/release-packaging/Classes/FluidBufSelect.sc @@ -30,17 +30,12 @@ FluidBufSelect : FluidBufProcessor { source.isNil.if {"FluidBufSelect: Invalid source buffer".throw}; destination.isNil.if {"FluidBufSelect: Invalid destination buffer".throw}; - indices = indices.asArray; channels = channels.asArray; - - - indices = [indices.size] ++ indices; + indices = [indices.size] ++ indices; channels = [channels.size] ++ channels; - indices.postln; - ^this.new(server, nil, [destination]).processList([source, destination]++ indices ++ channels ++ [1], freeWhenDone, action);//NB always blocking } From 48b1e806138437163639755e00dc31e61dbec861 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 23 Mar 2021 11:44:04 +0000 Subject: [PATCH 05/32] BufSTFT: help/doc and class naming changes --- release-packaging/Classes/FluidBufSTFT.sc | 52 +++--- .../HelpSource/Classes/FluidBufSTFT.schelp | 161 +++++++----------- 2 files changed, 84 insertions(+), 129 deletions(-) diff --git a/release-packaging/Classes/FluidBufSTFT.sc b/release-packaging/Classes/FluidBufSTFT.sc index 382cff6..bd0eb2d 100644 --- a/release-packaging/Classes/FluidBufSTFT.sc +++ b/release-packaging/Classes/FluidBufSTFT.sc @@ -1,47 +1,47 @@ FluidBufSTFT : FluidBufProcessor { - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse = 0,windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 1| - + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0,windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 1| + // source = source.asUGenInput; // source.isNil.if {"FluidBufScale: Invalid source buffer".throw}; - source = source ? -1; - magnitudeBuffer = magnitudeBuffer ? -1; - phaseBuffer = phaseBuffer ? -1; - resynthesisBuffer = resynthesisBuffer ? - 1; - - ^FluidProxyUgen.kr(\FluidBufSTFTTrigger, -1, source, startFrame, numFrames, startChan, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse, windowSize, hopSize, fftSize,trig, blocking); + source = source ? -1; + magnitude = magnitude ? -1; + phase = phase ? -1; + resynthesis = resynthesis ? - 1; + + ^FluidProxyUgen.kr(\FluidBufSTFTTrigger, -1, source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, windowSize, hopSize, fftSize,trig, blocking); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| - + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| + // source = source.asUGenInput; // source.isNil.if {"FluidBufSTFT: Invalid source buffer".throw}; - source = source ? -1; - magnitudeBuffer = magnitudeBuffer ? -1; - phaseBuffer = phaseBuffer ? -1; - resynthesisBuffer = resynthesisBuffer ? - 1; - + source = source ? -1; + magnitude = magnitude ? -1; + phase = phase ? -1; + resynthesis = resynthesis ? - 1; + ^this.new( - server, nil, [magnitudeBuffer,phaseBuffer,resynthesisBuffer].select{|b| b != -1} + server, nil, [magnitude,phase,resynthesis].select{|b| b != -1} ).processList( - [source, startFrame, numFrames, startChan, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse, windowSize, hopSize, fftSize, 0], freeWhenDone, action + [source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, windowSize, hopSize, fftSize, 0], freeWhenDone, action ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| - + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| + // source = source.asUGenInput; - source = source ? -1; - magnitudeBuffer = magnitudeBuffer ? -1; - phaseBuffer = phaseBuffer ? -1; - resynthesisBuffer = resynthesisBuffer ? - 1; - + source = source ? -1; + magnitude = magnitude ? -1; + phase = phase ? -1; + resynthesis = resynthesis ? - 1; + ^this.new( - server, nil, [magnitudeBuffer,phaseBuffer,resynthesisBuffer].select{|b| b != -1} + server, nil, [magnitude,phase,resynthesis].select{|b| b != -1} ).processList( - [source, startFrame, numFrames, startChan, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse, windowSize, hopSize, fftSize,1], freeWhenDone, action + [source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, windowSize, hopSize, fftSize,1], freeWhenDone, action ); } } diff --git a/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp b/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp index e9fe662..f86fcff 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp @@ -1,124 +1,63 @@ TITLE:: FluidBufSTFT -summary:: (put short description here) -categories:: Undocumented classes, UGens>Undocumented -related:: Classes/SomeRelatedClass, Reference/SomeRelatedStuff, etc. +summary:: Perform a Short-Time Fourier Transform on one channel of a buffer +categories:: FluidCorpusManipulation +related:: Classes/Buffer DESCRIPTION:: -(put long description here) +Performs either a forward or inverse Short-Time Fourier Transform (STFT) on a single channel source buffer~. In the forward case, resulting magnitudes and phases can be written to output buffers. In the inverse case, these buffers can be used to reconstruct the original source into a new buffer. -CLASSMETHODS:: - -METHOD:: processBlocking -(describe method here) - -ARGUMENT:: server -(describe argument here) - -ARGUMENT:: source -(describe argument here) - -ARGUMENT:: startFrame -(describe argument here) - -ARGUMENT:: numFrames -(describe argument here) - -ARGUMENT:: startChan -(describe argument here) +The magntude and phase buffers are laid out as (number of hops, number of bins). The number of hops is a function of the source length and the hop size. The number of bins is (1 + (fft size / 2)). -ARGUMENT:: magnitudeBuffer -(describe argument here) +The object is restricted to analysing a single source channel, because the channel counts of the magntude and phase buffers would quickly get out of hand otherwise. -ARGUMENT:: phaseBuffer -(describe argument here) - -ARGUMENT:: resynthesisBuffer -(describe argument here) - -ARGUMENT:: inverse -(describe argument here) - -ARGUMENT:: freeWhenDone -(describe argument here) - -ARGUMENT:: action -(describe argument here) +CLASSMETHODS:: -returns:: (describe returnvalue here) +private::new1 -METHOD:: process -(describe method here) +METHOD:: process, processBlocking +Run the process on the given sever, and perfrom code::action:: when done ARGUMENT:: server -(describe argument here) +The link::Classes/Server:: on which to run ARGUMENT:: source -(describe argument here) +The link::Classes/Buffer:: to use for the forward STFT ARGUMENT:: startFrame -(describe argument here) +The starting point for analysis in the source (in samples) ARGUMENT:: numFrames -(describe argument here) +The duration (in samples) to analyse ARGUMENT:: startChan -(describe argument here) +The channel to analyse -ARGUMENT:: magnitudeBuffer -(describe argument here) +ARGUMENT:: magnitude +The link::Classes/Buffer:: to write magnitudes to in the forward case, or read from in the inverse case. This is optional for the forward transform, mandatory for the inverse. -ARGUMENT:: phaseBuffer -(describe argument here) +ARGUMENT:: phase +The link::Classes/Buffer:: to write phases to in the forward case, or read from in the inverse case. This is optional for the forward transform, mandatory for the inverse. -ARGUMENT:: resynthesisBuffer -(describe argument here) +ARGUMENT:: resynthesis +The link::Classes/Buffer:: to write re-synthesised data to in the inverse case. Ignored for the forward transform. Mandatory in the inverse case. ARGUMENT:: inverse -(describe argument here) +When set to 1, an inverse STFT is performed, and the resynthesised data is written to the resynthesis buffer using overlap-add. -ARGUMENT:: freeWhenDone -(describe argument here) - -ARGUMENT:: action -(describe argument here) +ARGUMENT:: windowSize +The number of source samples that are analysed at once. -returns:: (describe returnvalue here) +ARGUMENT:: hopSize +How many samples there are in-between analysis windows. The -1 default value will default to half of windowSize (overlap of 2). -METHOD:: kr -(describe method here) +ARGUMENT:: fftSize +The FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. For this object it is effectively capped at 65536. -ARGUMENT:: source -(describe argument here) - -ARGUMENT:: startFrame -(describe argument here) - -ARGUMENT:: numFrames -(describe argument here) - -ARGUMENT:: startChan -(describe argument here) - -ARGUMENT:: magnitudeBuffer -(describe argument here) - -ARGUMENT:: phaseBuffer -(describe argument here) - -ARGUMENT:: resynthesisBuffer -(describe argument here) - -ARGUMENT:: inverse -(describe argument here) - -ARGUMENT:: trig -(describe argument here) - -ARGUMENT:: blocking -(describe argument here) - -returns:: (describe returnvalue here) +ARGUMENT:: freeWhenDone +Free the server instance when processing complete. Default true +ARGUMENT:: action +Runs when processing is complete INSTANCEMETHODS:: @@ -128,27 +67,43 @@ EXAMPLES:: code:: s.reboot ( -b = Buffer.read(s,File.realpath(FluidBufSTFT.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav"); +b = Buffer.read(s,File.realpath(FluidBufSTFT.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); m = Buffer.new; p = Buffer.new; r = Buffer.new; ) -b + ( fork{ - FluidBufSTFT.process(s,source:b,magnitudeBuffer:m,phaseBuffer:p).wait; - FluidBufSTFT.process(s,magnitudeBuffer:m,phaseBuffer:p,resynthesisBuffer:r,inverse:1).wait; - "Done".postln; + FluidBufSTFT.process(s,source:b,magnitude:m,phase:p).wait; + FluidBufSTFT.process(s,magnitude:m,phase:p,resynthesis:r,inverse:1).wait; + "Done".postln; } ) +FluidBufSTFT.process(s,source:b,magnitude:m,phase:p) +m.getn(4444,10,{|x|x.postln;}) -{ PlayBuf.ar(1,r); }.play - -//null? -{ PlayBuf.ar(1,r) - PlayBuf(1,b); }.play - +{ PlayBuf.ar(1,r); }.play +//nullsum +{ PlayBuf.ar(1,r) - PlayBuf(1,b); }.play +//draw the magnitudes as a greyscale spectrogram +// make the image +i = Image.new(m.numFrames, m.numChannels) +//retreive the image and assign to pixels +( +m.loadToFloatArray(action: {|x| + var mod = m.numChannels; + { + x.do{ + |val, index| + i.setColor(Color.gray(val), index.div(mod), mod - 1 - index.mod(mod)); + }; + i.plot("spectrogram", showInfo: false); + }.fork(AppClock) +}); +) :: From 54db1f74c77223be92ccaa1f777d7d6079d78ca4 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 24 Mar 2021 10:39:02 +0000 Subject: [PATCH 06/32] added setPoint to Dataset --- release-packaging/Classes/FluidDataSet.sc | 12 +++++++++++- .../HelpSource/Classes/FluidDataSet.schelp | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/release-packaging/Classes/FluidDataSet.sc b/release-packaging/Classes/FluidDataSet.sc index 9df17cc..9cad494 100644 --- a/release-packaging/Classes/FluidDataSet.sc +++ b/release-packaging/Classes/FluidDataSet.sc @@ -40,7 +40,17 @@ FluidDataSet : FluidDataObject this.prSendMsg(this.deletePointMsg(label)); } - clearMsg { ^this.prMakeMsg(\clear,id); } + setPointMsg{|label,buffer| + buffer = this.prEncodeBuffer(buffer); + ^this.prMakeMsg(\setPoint,id,label.asSymbol,buffer); + } + + setPoint{|label, buffer, action| + actions[\setPoint] = [nil,action]; + this.prSendMsg(this.setPointMsg(label,buffer)); + } + + clearMsg { ^this.prMakeMsg(\clear,id); } clear { |action| actions[\clear] = [nil,action]; diff --git a/release-packaging/HelpSource/Classes/FluidDataSet.schelp b/release-packaging/HelpSource/Classes/FluidDataSet.schelp index 8816b16..eea1ed8 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSet.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSet.schelp @@ -41,6 +41,9 @@ Retrieve a point from the data set into a link::Classes/Buffer::. Will report an METHOD:: deletePoint Remove a point from the data set. Will report an error if the label doesn't exist. + +METHOD:: setPoint +Set the point: if the label exists, this method behaves like updatePoint; if the label doesn't exist, behaves like addPoint. ​​ METHOD:: clear Empty the data set. From 59d4bcb20da9675fcb2591aca39703a5b8a43fc6 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 24 Mar 2021 15:51:33 +0000 Subject: [PATCH 07/32] dataset to/from buffer + getIds --- release-packaging/Classes/FluidDataSet.sc | 30 +++++ .../HelpSource/Classes/FluidDataSet.schelp | 105 +++++++++++++++--- 2 files changed, 119 insertions(+), 16 deletions(-) diff --git a/release-packaging/Classes/FluidDataSet.sc b/release-packaging/Classes/FluidDataSet.sc index 9cad494..5349e92 100644 --- a/release-packaging/Classes/FluidDataSet.sc +++ b/release-packaging/Classes/FluidDataSet.sc @@ -72,4 +72,34 @@ FluidDataSet : FluidDataObject actions[\print] = [string(FluidMessageResponse,_,_),action]; this.prSendMsg(this.printMsg); } + + toBufferMsg{|buffer, transpose = 0, labelSet| + buffer = this.prEncodeBuffer(buffer); + ^this.prMakeMsg(\toBuffer, id, buffer, transpose, labelSet.asUGenInput); + } + + toBuffer{|buffer, transpose = 0, labelSet, action| + actions[\toBuffer] = [nil,action]; + this.prSendMsg(this.toBufferMsg(buffer, transpose, labelSet)); + } + + fromBufferMsg{|buffer, transpose = 0, labelSet| + buffer = this.prEncodeBuffer(buffer); + ^this.prMakeMsg(\fromBuffer, id, buffer, transpose, labelSet.asUGenInput); + } + + fromBuffer{|buffer, transpose = 0, labelSet, action| + actions[\fromBuffer] = [nil,action]; + this.prSendMsg(this.fromBufferMsg(buffer, transpose, labelSet)); + } + + getIdsMsg{|labelSet| + ^this.prMakeMsg(\getIds, id, labelSet.asUGenInput); + } + + getIds{|labelSet, action| + actions[\getIds] = [nil,action]; + this.prSendMsg(this.getIdsMsg(labelSet)); + } } + diff --git a/release-packaging/HelpSource/Classes/FluidDataSet.schelp b/release-packaging/HelpSource/Classes/FluidDataSet.schelp index eea1ed8..71cb782 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSet.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSet.schelp @@ -47,6 +47,36 @@ Set the point: if the label exists, this method behaves like updatePoint; if the ​​ METHOD:: clear Empty the data set. + +METHOD:: toBuffer +Dump the content of the dataset to a link::Classes/Buffer::, with optional transposition, and a map of channel/frames to the original IDs as link::Classes/FluidLabelSet::. + +ARGUMENT:: buffer +The buffer to write to. It will be resized. + +ARGUMENT:: transpose +If 0, each dataset point becomes a channel, and each dataset dimension becomes a frame. If 1, points become frames, and dimensions become channels. + +ARGUMENT:: labelSet +The labelset in which to dump the point's IDs associated with their reference channel number (or frame number if transposed). + +ARGUMENT:: action +A function to run when the dump is done. + +METHOD:: fromBuffer +Import to the dataset the content of a link::Classes/Buffer::, with optional transposition, and a map of channel/frames to the original IDs as link::Classes/FluidLabelSet::. + +ARGUMENT:: buffer +The buffer to read from. The dataset will be resized. + +ARGUMENT:: transpose +If 0, each channel becomes a dataset point, and each frame becomes a dataset dimension. If 1, frames become points, and channels become dimensions. + +ARGUMENT:: labelSet +The labelset from which to retrieve the point's IDs associated with their reference channel number (or frame number if transposed). + +ARGUMENT:: action +A function to run when the import is done. ​ METHOD:: merge Merge sourceDataSet in the current DataSet. It will update the value of points with the same label if overwrite is set to 1. To add columns instead, see the 'transformJoin' method of link::Classes/FluidDataSetQuery:: @@ -76,13 +106,13 @@ fork{ ~point = Buffer.alloc(s,1,1); s.sync; 10.do{|i| - ~point.set(0,i); - ~ds.addPoint(i.asString,~point,{("addPoint"+i).postln}); - s.sync; - }; - ~ds.dump; - s.sync; - ~ds.free; + ~point.set(0,i); + ~ds.addPoint(i.asString,~point,{("addPoint"+i).postln}); + s.sync; + }; + ~ds.dump; + s.sync; + ~ds.free; }; ) @@ -92,9 +122,9 @@ d = Dictionary.new; d.add(\cols -> 1); d.add(\data -> Dictionary.newFrom(10.collect{|i|[i.asString, [i.asFloat]]}.flatten)); fork{ - ~ds = FluidDataSet.new(s); - ~ds.load(d); s.sync; - ~ds.dump; s.sync; ~ds.free; + ~ds = FluidDataSet.new(s); + ~ds.load(d); s.sync; + ~ds.dump; s.sync; ~ds.free; } ) @@ -102,16 +132,59 @@ fork{ ( ~ds = FluidDataSet.new(s); { - var trig = Impulse.kr(20); - var count = PulseCount.kr(trig) - 1; - var buf = LocalBuf(1); - BufWr.kr(count, buf); - FluidDataSetWr.kr(~ds.asUGenInput, buf: buf, trig: trig); - FreeSelf.kr(count - 8); + var trig = Impulse.kr(20); + var count = PulseCount.kr(trig) - 1; + var buf = LocalBuf(1); + BufWr.kr(count, buf); + FluidDataSetWr.kr(~ds.asUGenInput, buf: buf, trig: trig); + FreeSelf.kr(count - 8); }.play.onFree{~ds.dump{|o| o.postln;~ds.free}} ) :: +STRONG:: Buffer Interface:: +As the content of the dataset has a similar structure to buffers, namely arrays of floats in parallel, it is possible to transfer the content between the two. Careful consideration of the rotation of the buffer, as well as the relation of points to channel numbers, are needed. + +code:: +( +//Make a dummy data set +d = FluidDataSet(s); +~data = Dictionary.with(*Array.iota(20).reshape(4,5).collect{|a,i| ("row"++i)->a}); +~dsdata = Dictionary.newFrom([\cols,5,\data,~data]); +d.load(~dsdata); +d.print; +) + +//convert to separate buffer and labelset +b = Buffer(s); +l = FluidLabelSet(s); +d.toBuffer(b,0,l); + +//check the result: by default, dataset points become channels, with their associated data as sample frames +b.query +b.getn(0,20,{|x|x.postln}) +l.print + +//you can also transpose your query, where dataset points are each a sample frame, and each data column becomes a channel +d.toBuffer(b,1,l); +b.query +b.getn(0,20,{|x|x.postln}) +//note that the IDs are still one per item, as columns are unamed in datasets +l.print + +//Convert back to DS again +e = FluidDataSet(s); + +//Let's use the transposed data we just got +e.print; +e.fromBuffer(b,1,l); +e.print; +//if we didn't transpose, we would get an error as the labelset is mismatched with the number of items +e.clear +e.print +e.fromBuffer(b,0,l) +:: + STRONG:: Merging Datasets:: code:: //this is how to add items between 2 datasets. From 3ec019e410f0728e46ebeffb5eb00a3159c6260f Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Thu, 25 Mar 2021 12:10:22 +0000 Subject: [PATCH 08/32] dataset to/from buffer class def now updates the buffers --- release-packaging/Classes/FluidDataSet.sc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release-packaging/Classes/FluidDataSet.sc b/release-packaging/Classes/FluidDataSet.sc index 5349e92..12c7edb 100644 --- a/release-packaging/Classes/FluidDataSet.sc +++ b/release-packaging/Classes/FluidDataSet.sc @@ -42,7 +42,7 @@ FluidDataSet : FluidDataObject setPointMsg{|label,buffer| buffer = this.prEncodeBuffer(buffer); - ^this.prMakeMsg(\setPoint,id,label.asSymbol,buffer); + ^this.prMakeMsg(\setPoint,id,label.asSymbol,buffer,["/b_query",buffer.asUGenInput]); } setPoint{|label, buffer, action| @@ -75,7 +75,7 @@ FluidDataSet : FluidDataObject toBufferMsg{|buffer, transpose = 0, labelSet| buffer = this.prEncodeBuffer(buffer); - ^this.prMakeMsg(\toBuffer, id, buffer, transpose, labelSet.asUGenInput); + ^this.prMakeMsg(\toBuffer, id, buffer, transpose, labelSet.asUGenInput,["/b_query",buffer.asUGenInput]); } toBuffer{|buffer, transpose = 0, labelSet, action| @@ -85,7 +85,7 @@ FluidDataSet : FluidDataObject fromBufferMsg{|buffer, transpose = 0, labelSet| buffer = this.prEncodeBuffer(buffer); - ^this.prMakeMsg(\fromBuffer, id, buffer, transpose, labelSet.asUGenInput); + ^this.prMakeMsg(\fromBuffer, id, buffer, transpose, labelSet.asUGenInput,["/b_query",buffer.asUGenInput]); } fromBuffer{|buffer, transpose = 0, labelSet, action| From 4fbd3d25581db89bd60e2fd2165e38e84b1c3a57 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Thu, 25 Mar 2021 12:11:07 +0000 Subject: [PATCH 09/32] kmeans new functionalities - classes done, with help+doc+examples in progress --- release-packaging/Classes/FluidKMeans.sc | 120 ++++++++++++------ .../HelpSource/Classes/FluidKMeans.schelp | 72 +++++++++++ 2 files changed, 154 insertions(+), 38 deletions(-) diff --git a/release-packaging/Classes/FluidKMeans.sc b/release-packaging/Classes/FluidKMeans.sc index a38d613..c131850 100644 --- a/release-packaging/Classes/FluidKMeans.sc +++ b/release-packaging/Classes/FluidKMeans.sc @@ -1,70 +1,114 @@ FluidKMeans : FluidRealTimeModel { - var clusters, maxiter; + var clusters, maxiter; *new {|server, numClusters = 4, maxIter = 100| ^super.new(server,[numClusters,maxIter]) - .numClusters_(numClusters) - .maxIter_(maxIter); + .numClusters_(numClusters) + .maxIter_(maxIter); } - numClusters_{|n| clusters = n.asInteger} - numClusters{ ^clusters } + numClusters_{|n| clusters = n.asInteger} + numClusters{ ^clusters } - maxIter_{|i| maxiter = i.asInteger} - maxIter{ ^maxiter } + maxIter_{|i| maxiter = i.asInteger} + maxIter{ ^maxiter } - prGetParams{^[this.numClusters,this.maxIter,-1,-1];} + prGetParams{^[this.numClusters,this.maxIter,-1,-1];} - fitMsg{ |dataSet| ^this.prMakeMsg(\fit,id,dataSet.id);} + fitMsg{ |dataSet| ^this.prMakeMsg(\fit,id,dataSet.id);} - fit{|dataSet, action| - actions[\fit] = [ - numbers( FluidMessageResponse, _, this.numClusters ,_), - action - ]; - this.prSendMsg(this.fitMsg(dataSet)); - } + fit{|dataSet, action| + actions[\fit] = [ + numbers( FluidMessageResponse, _, this.numClusters ,_), + action + ]; + this.prSendMsg(this.fitMsg(dataSet)); + } - fitPredictMsg{|dataSet, labelSet| - ^this.prMakeMsg(\fitPredict, id, dataSet.id, labelSet.id) - } + fitPredictMsg{|dataSet, labelSet| + ^this.prMakeMsg(\fitPredict, id, dataSet.id, labelSet.id) + } fitPredict{|dataSet, labelSet,action| - actions[\fitPredict] = [ - numbers(FluidMessageResponse, _, this.numClusters, _), - action - ]; + actions[\fitPredict] = [ + numbers(FluidMessageResponse, _, this.numClusters, _), + action + ]; this.prSendMsg(this.fitPredictMsg(dataSet,labelSet)); } - predictMsg{|dataSet, labelSet| - ^this.prMakeMsg(\predict, id, dataSet.id, labelSet.id) - } + predictMsg{|dataSet, labelSet| + ^this.prMakeMsg(\predict, id, dataSet.id, labelSet.id) + } predict{ |dataSet, labelSet, action| - actions[\predict] = [ - numbers(FluidMessageResponse, _, this.numClusters, _), - action - ]; + actions[\predict] = [ + numbers(FluidMessageResponse, _, this.numClusters, _), + action + ]; this.prSendMsg(this.predictMsg(dataSet,labelSet)); } - predictPointMsg{|buffer| - ^this.prMakeMsg(\predictPoint, id, this.prEncodeBuffer(buffer)) - } + predictPointMsg{|buffer| + ^this.prMakeMsg(\predictPoint, id, this.prEncodeBuffer(buffer)) + } predictPoint { |buffer, action| actions[\predictPoint] = [number(FluidMessageResponse,_,_),action]; this.prSendMsg(this.predictPointMsg(buffer)) } - kr{|trig, inputBuffer,outputBuffer| - ^FluidKMeansQuery.kr(K2A.ar(trig), - this, clusters, maxiter, - this.prEncodeBuffer(inputBuffer), - this.prEncodeBuffer(outputBuffer)); + fitTransformMsg{|srcDataSet, dstDataSet| + ^this.prMakeMsg(\fitTransform, id, srcDataSet.id, dstDataSet.id) + } + + fitTransform{|srcDataSet, dstDataSet,action| + actions[\fitTransform] = [nil,action]; + this.prSendMsg(this.fitTransformMsg(srcDataSet,dstDataSet)); + } + + transformMsg{|srcDataSet, dstDataSet| + ^this.prMakeMsg(\transform, id, srcDataSet.id, dstDataSet.id) + } + + transform{ |srcDataSet, dstDataSet, action| + actions[\transform] = [nil,action]; + this.prSendMsg(this.transformMsg(srcDataSet,dstDataSet)); + } + + transformPointMsg{ |sourceBuffer, targetBuffer| + ^this.prMakeMsg(\transformPoint, id, + this.prEncodeBuffer(sourceBuffer), + this.prEncodeBuffer(targetBuffer), + ["/b_query", targetBuffer.asUGenInput]); } + + transformPoint { |sourceBuffer, targetBuffer, action| + actions[\transformPoint] = [nil,{action.value(targetBuffer)}]; + this.prSendMsg(this.transformPointMsg(sourceBuffer, targetBuffer)); + } + + getMeansMsg{|dataSet| ^this.prMakeMsg(\getMeans, id, dataSet.asUGenInput) } + + getMeans{ |dataSet, action| + actions[\getMeans] = [nil, action]; + this.prSendMsg(this.getMeansMsg(dataSet)); + } + + setMeansMsg{|dataSet| ^this.prMakeMsg(\setMeans, id, dataSet.asUGenInput) } + + setMeans{ |dataSet, action| + actions[\setMeans] = [nil, action]; + this.prSendMsg(this.setMeansMsg(dataSet)); + } + + kr{|trig, inputBuffer,outputBuffer| + ^FluidKMeansQuery.kr(K2A.ar(trig), + this, clusters, maxiter, + this.prEncodeBuffer(inputBuffer), + this.prEncodeBuffer(outputBuffer)); + } } FluidKMeansQuery : FluidRTQuery {} diff --git a/release-packaging/HelpSource/Classes/FluidKMeans.schelp b/release-packaging/HelpSource/Classes/FluidKMeans.schelp index 28f0ef3..0ce4e39 100644 --- a/release-packaging/HelpSource/Classes/FluidKMeans.schelp +++ b/release-packaging/HelpSource/Classes/FluidKMeans.schelp @@ -65,6 +65,46 @@ A link::Classes/FluidLabelSet:: to contain assignments. ARGUMENT:: action A function to run when complete, taking an array of the counts for each category as its argument. +METHOD:: fitTransform +Run link::Classes/FluidKMeans#*fit:: and link::Classes/FluidKMeans#*predict:: in a single pass: i.e. train the model on the incoming link::Classes/FluidDataSet:: and then return the learned clustering to the passed link::Classes/FluidLabelSet:: +ARGUMENT:: srcDataSet +a link::Classes/FluidDataSet:: containing the data to fit and predict. +ARGUMENT:: dstDataSet +a link::Classes/FluidLabelSet:: to retrieve the predicted clusters. +ARGUMENT:: action +A function to run when the server responds + +METHOD:: transformPoint +Given a trained object, return the cluster ID for a data point in a link::Classes/Buffer:: +ARGUMENT:: sourceBuffer +a link::Classes/Buffer:: containing a data point. +ARGUMENT:: targetBuffer +a link::Classes/Buffer:: containing a data point. +ARGUMENT:: action +A function to run when the server responds, taking the ID of the cluster as its argument. + +METHOD:: transform +Report cluster assignments for previously unseen data. +ARGUMENT:: srcDataSet +A link::Classes/FluidDataSet:: of data points. +ARGUMENT:: dstDataSet +A link::Classes/FluidLabelSet:: to contain assignments. +ARGUMENT:: action +A function to run when complete, taking an array of the counts for each category as its argument. + +METHOD:: getMeans +Report cluster assignments for previously unseen data. +ARGUMENT:: dataSet +A link::Classes/FluidDataSet:: of data points. +ARGUMENT:: action +A function to run when complete, taking an array of the counts for each category as its argument. + +METHOD:: setMeans +Report cluster assignments for previously unseen data. +ARGUMENT:: dataSet +A link::Classes/FluidDataSet:: of data points. +ARGUMENT:: action +A function to run when complete, taking an array of the counts for each category as its argument. EXAMPLES:: code:: @@ -147,6 +187,38 @@ w.front; ~kmeans.predictPoint(~inbuf,{|x|x.postln;}); :: +subsection:: Accessing the means + +We can get and set the means for each cluster, their centroid. + +code:: +~centroids = FluidDataSet(s); +~kmeans.getMeans(~centroids, {~centroids.print}); + + + +~centroids.load(Dictionary.newFrom([\cols, 2, \data, Dictionary.newFrom([\0, [0.5,0.5], \1, [-0.5,0.5], \2, [0.5,-0.5], \3, [-0.5,-0.5]])])); +~centroids.print +~kmeans.setMeans(~centroids, {~kmeans.predict(~dataSet,~clusters,{~clusters.dump{|x|var count = 0.dup(4); x["data"].keysValuesDo{|k,v|count[v[0].asInteger] = count[v[0].asInteger] + 1;};count.postln}})}); + +~kmeans.free +~kmeans = FluidKMeans(s); +~kmeans.predict(~dataSet,~clusters) + +:: + +subsection:: Cluster-distance Space + +You can get the euclidian distance of a given point to each cluster. + +code:: +b = Buffer.sendCollection(s,[0.5,0.5]) +c = Buffer(s) + +~kmeans.transformPoint(b,c,{|x|x.query;x.getn(0,x.numFrames,{|y|y.postln})}) + +:: + subsection:: Queries in a Synth This is the equivalent of predictPoint, but wholly on the server From 6c95820d837c0d9c1db1c0332b4896e425378692 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Thu, 25 Mar 2021 19:21:27 +0000 Subject: [PATCH 10/32] kmeans now have working clear message and accumulative training. --- release-packaging/Classes/FluidKMeans.sc | 7 +++++++ release-packaging/HelpSource/Classes/FluidKMeans.schelp | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/release-packaging/Classes/FluidKMeans.sc b/release-packaging/Classes/FluidKMeans.sc index c131850..31fda02 100644 --- a/release-packaging/Classes/FluidKMeans.sc +++ b/release-packaging/Classes/FluidKMeans.sc @@ -103,6 +103,13 @@ FluidKMeans : FluidRealTimeModel { this.prSendMsg(this.setMeansMsg(dataSet)); } + clearMsg{ ^this.prMakeMsg(\clear, id) } + + clear{ |action| + actions[\clear] = [nil, action]; + this.prSendMsg(this.clearMsg); + } + kr{|trig, inputBuffer,outputBuffer| ^FluidKMeansQuery.kr(K2A.ar(trig), this, clusters, maxiter, diff --git a/release-packaging/HelpSource/Classes/FluidKMeans.schelp b/release-packaging/HelpSource/Classes/FluidKMeans.schelp index 0ce4e39..8c49e9a 100644 --- a/release-packaging/HelpSource/Classes/FluidKMeans.schelp +++ b/release-packaging/HelpSource/Classes/FluidKMeans.schelp @@ -201,8 +201,7 @@ code:: ~centroids.print ~kmeans.setMeans(~centroids, {~kmeans.predict(~dataSet,~clusters,{~clusters.dump{|x|var count = 0.dup(4); x["data"].keysValuesDo{|k,v|count[v[0].asInteger] = count[v[0].asInteger] + 1;};count.postln}})}); -~kmeans.free -~kmeans = FluidKMeans(s); +~kmeans.clear ~kmeans.predict(~dataSet,~clusters) :: From 1aa3185fe60432bf7e7f9f19de65891e8aa84659 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 31 Mar 2021 12:26:06 +0100 Subject: [PATCH 11/32] dataset: corrected the transposition documentation of to/from buffer --- .../HelpSource/Classes/FluidDataSet.schelp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidDataSet.schelp b/release-packaging/HelpSource/Classes/FluidDataSet.schelp index 71cb782..b28cbaf 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSet.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSet.schelp @@ -49,31 +49,31 @@ METHOD:: clear Empty the data set. METHOD:: toBuffer -Dump the content of the dataset to a link::Classes/Buffer::, with optional transposition, and a map of channel/frames to the original IDs as link::Classes/FluidLabelSet::. +Dump the content of the dataset to a link::Classes/Buffer::, with optional transposition, and a map of frames/channels to the original IDs as a link::Classes/FluidLabelSet::. ARGUMENT:: buffer The buffer to write to. It will be resized. ARGUMENT:: transpose -If 0, each dataset point becomes a channel, and each dataset dimension becomes a frame. If 1, points become frames, and dimensions become channels. +If 0, each dataset point becomes a buffer frame, and each dataset dimension becomes a buffer channel. If 1, points become channels, and dimensions become frames. ARGUMENT:: labelSet -The labelset in which to dump the point's IDs associated with their reference channel number (or frame number if transposed). +The link::Classes/FluidLabelSet:: in which to dump the point's IDs associated with their reference frame number (or channel number if transposed). ARGUMENT:: action A function to run when the dump is done. METHOD:: fromBuffer -Import to the dataset the content of a link::Classes/Buffer::, with optional transposition, and a map of channel/frames to the original IDs as link::Classes/FluidLabelSet::. +Import to the dataset the content of a link::Classes/Buffer::, with optional transposition, and a map of frames/channels to the original IDs as a link::Classes/FluidLabelSet::. ARGUMENT:: buffer The buffer to read from. The dataset will be resized. ARGUMENT:: transpose -If 0, each channel becomes a dataset point, and each frame becomes a dataset dimension. If 1, frames become points, and channels become dimensions. +If 0, each buffer frame becomes a dataset point, and each buffer channel becomes a dataset dimension. If 1, channels become points, and frames become dimensions. ARGUMENT:: labelSet -The labelset from which to retrieve the point's IDs associated with their reference channel number (or frame number if transposed). +The link::Classes/FluidLabelSet:: from which to retrieve the point's IDs associated with their reference frame number (or channel number if transposed). ARGUMENT:: action A function to run when the import is done. @@ -143,6 +143,7 @@ fork{ :: STRONG:: Buffer Interface:: + As the content of the dataset has a similar structure to buffers, namely arrays of floats in parallel, it is possible to transfer the content between the two. Careful consideration of the rotation of the buffer, as well as the relation of points to channel numbers, are needed. code:: @@ -160,12 +161,12 @@ b = Buffer(s); l = FluidLabelSet(s); d.toBuffer(b,0,l); -//check the result: by default, dataset points become channels, with their associated data as sample frames +//check the result: by default, dataset points become frames, with their associated data columns as channels b.query b.getn(0,20,{|x|x.postln}) l.print -//you can also transpose your query, where dataset points are each a sample frame, and each data column becomes a channel +//you can also transpose your query, where dataset points are each a buffer channel, and each data column becomes a buffer frame d.toBuffer(b,1,l); b.query b.getn(0,20,{|x|x.postln}) From 57fd2a54df34a8bef4fe2cec5a67e94d0c0532a6 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 6 Apr 2021 12:44:49 +0100 Subject: [PATCH 12/32] Update FluidDataSetWr to use SetPoint, remove auto index --- include/clients/rt/FluidDataSetWr.hpp | 68 ++++++++++--------- release-packaging/Classes/FluidDataSetWr.sc | 10 +-- .../HelpSource/Classes/FluidDataSetWr.schelp | 37 +++++++--- 3 files changed, 69 insertions(+), 46 deletions(-) diff --git a/include/clients/rt/FluidDataSetWr.hpp b/include/clients/rt/FluidDataSetWr.hpp index ebdc0a4..ab13df0 100644 --- a/include/clients/rt/FluidDataSetWr.hpp +++ b/include/clients/rt/FluidDataSetWr.hpp @@ -20,39 +20,45 @@ namespace fluid { namespace client { -class DataSetWriterClient : public FluidBaseClient, OfflineIn, OfflineOut -{ +class DataSetWriterClient : public FluidBaseClient, OfflineIn, OfflineOut { + enum { kDataSet, kIDPrefix, kIDNumber, kBuffer }; + static constexpr std::initializer_list idNumberDefaults{0, 0}; + public: - FLUID_DECLARE_PARAMS( - DataSetClientRef::makeParam("dataSet", "DataSet ID"), - StringParam("labelPrefix","Label Prefix"), - LongParam("labelOffset", "Label Counter Offset", 0), - BufferParam("buf", "Data Buffer") - ); - - DataSetWriterClient(ParamSetViewType& p) : mParams(p) {} - - template - Result process(FluidContext&) - { - auto dataset = get<0>().get(); - if (auto datasetPtr = dataset.lock()) - { - std::stringstream ss; - ss << get<1>(); - - index labelOffset = get<2>(); - if(labelOffset >= 0) ss << labelOffset + (mCounter++); - - auto buf = get<3>(); - return datasetPtr->addPoint(ss.str(), buf); - } - else - return {Result::Status::kError, "No dataset"}; + FLUID_DECLARE_PARAMS(DataSetClientRef::makeParam("dataSet", "DataSet ID"), + StringParam("idPrefix", "ID Prefix"), + LongArrayParam("idNumber", "ID Counter Offset", + idNumberDefaults), + BufferParam("buf", "Data Buffer")); + + DataSetWriterClient(ParamSetViewType &p) : mParams(p) {} + + template Result process(FluidContext &) { + auto dataset = get().get(); + if (auto datasetPtr = dataset.lock()) { + std::string &idPrefix = get(); + auto &idNumberArr = get(); + if (idNumberArr.size() != 2) + return {Result::Status::kError, "ID number malformed"}; + if (idPrefix.size() == 0 && idNumberArr[0] == 0) + return {Result::Status::kError, "No ID supplied"}; + + mStream.clear(); + mStream.seekp(0); + + mStream << idPrefix; + + if (idNumberArr[0] > 0) + mStream << idNumberArr[1]; + + auto buf = get(); + return datasetPtr->setPoint(mStream.str(), buf); + } else + return {Result::Status::kError, "No DataSet"}; } - - private: - index mCounter{0}; + +private: + std::ostringstream mStream; }; using NRTThreadedDataSetWriter = diff --git a/release-packaging/Classes/FluidDataSetWr.sc b/release-packaging/Classes/FluidDataSetWr.sc index db4f79d..c72c12d 100644 --- a/release-packaging/Classes/FluidDataSetWr.sc +++ b/release-packaging/Classes/FluidDataSetWr.sc @@ -1,10 +1,12 @@ FluidDataSetWr : FluidBufProcessor { - *kr { |dataset,labelPrefix = "", labelOffset = 0,buf, trig=1, blocking = 1| + *kr { |dataset,idPrefix = "", idNumber = 0,buf, trig=1, blocking = 1| var args; - buf ?? {"No input buffer provided".error}; - labelPrefix = labelPrefix !? {[labelPrefix.asString.size] ++ labelPrefix.asString.ascii} ?? {0}; + buf ?? {(this.class.name ++ ": No input buffer provided").error}; + + idNumber = idNumber !? {[2,1,idNumber.asInteger.asUGenInput]} ?? {[2,0,0]}; + idPrefix = idPrefix !? {[idPrefix.asString.size] ++ idPrefix.asString.ascii} ?? {0}; - args = [-1] ++ dataset.asUGenInput ++labelPrefix ++ labelOffset.asInteger.asUGenInput ++buf.asUGenInput ++ trig ++ blocking; + args = [-1] ++ dataset.asUGenInput ++idPrefix ++ idNumber ++ buf.asUGenInput ++ trig ++ blocking; ^FluidProxyUgen.kr(\FluidDataSetWrTrigger,*args); } diff --git a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp index e797c52..ad7dcc3 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp @@ -4,9 +4,9 @@ categories:: FluidManipulation related:: Classes/FLuidDataSet DESCRIPTION:: -A UGen that adds labelled points to a link::Classes/FluidDataSet:: +A UGen that adds labelled points to a link::Classes/FluidDataSet:: Internally, this calls code::setPoint::, so IDs that already exist will be overwritten, and new IDs will be added. The actual work is done on the server's command queue, rather than the real-thread. -By default the object generates a numerical index that gets used for the point labels. This index starts counting from link::#offset#labelOffset:: and increments each time the Ugen is retriggered with a zero to non-zero transition. The label is then concatenated with the code::labelPrefix:: symbol, which is fixed at instantiation. In this way, one can make custom, incrementing labels, e.g. +By default the object generates a numerical index that gets used for the point labels. This index starts counting from link::#offset#labelOffset:: and increments each time the Ugen is re-triggered with a zero to non-zero transition. The label is then concatenated with the code::idPrefix:: symbol, which is fixed at instantiation. In this way, one can make custom, incrementing labels, e.g. code:: FluidDataSetWr.kr(~somedataset,"my_data",0,~somebuffer,trig) @@ -14,7 +14,7 @@ FluidDataSetWr.kr(~somedataset,"my_data",0,~somebuffer,trig) would add points like code::my_data0, mydata1, mydata2...:: if successively retriggered. -Alternatively, for one shot use you may not want a numerical suffix at all. Setting code::indexLabel:: < 0 will bypass this and use only the labelPrefix. As such, any retriggering will result in a complaint from the link::Classes/FluidDataSet:: that the requested label is already present. +Alternatively, for one shot use you may not want a numerical suffix at all. Setting code::idNumber:: to code:: nil:: will bypass this and use only the code::idPrefix:: string. CLASSMETHODS:: @@ -26,12 +26,12 @@ The equivalent of calling link::Classes/FluidDataSet#-addPoint::, but within a l ARGUMENT:: dataset An instance of link::Classes/FluidDataSet:: or an instance's name. -ARGUMENT:: labelPrefix +ARGUMENT:: idPrefix A string or symbol with a prefix for generated labels -ARGUMENT:: labelOffset +ARGUMENT:: idNumber ANCHOR::offset:: -An integer with the offset to start labeling from. If the UGen is run in a server-side loop (i.e. repeatedly retriggered), the generated labels will count upwards from this offset. If < 0, then no numerical index will be applied to the generated label (i.e. only the labelPrefix is used). +An integer with the offset to start labeling from. If the UGen is run in a server-side loop (i.e. repeatedly re-triggered), the generated labels will count upwards from this offset. If < 0, then no numerical index will be applied to the generated label (i.e. only the labelPrefix is used). ARGUMENT:: buf The link::Classes/Buffer:: containing the data point. @@ -40,6 +40,10 @@ ARGUMENT:: trig A kr trigger signal +ARGUMENT:: blocking + +If 0 then the job will run in its own thread (not reccomended for this object) + EXAMPLES:: code:: @@ -48,13 +52,24 @@ s.reboot; ~ds = FluidDataSet(s); ) +//Write a 100 points whose values increase ( -{ +~ds.clear; +OSCFunc({ + "FluidDataSetWr help: all points written".postln; + ~ds.print +},'/datasetwrdone').oneShot; + +{ |n| var b = LocalBuf.newFrom([0,1,2,3]); - FreeSelfWhenDone.kr(FluidDataSetWr.kr(~ds,"help_data_point",buf:b)); -}.play(s); + var trig = Impulse.kr(ControlRate.ir / 2); + var idx = Stepper.kr(trig,min:0,max:n); + 4.collect{|i| BufWr.kr([(4 * idx) + i],b,i)}; + FluidDataSetWr.kr(~ds,idNumber:idx,buf:b,trig:trig); + SendReply.kr(idx >= n, '/datasetwrdone'); + FreeSelf.kr(idx >= n); + +}.play(s,args:[n:100]); ) -~ds.print; - :: From fbd6dd7154a1bb6c5b7038b72f572734012ba456 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 6 Apr 2021 12:45:31 +0100 Subject: [PATCH 13/32] Remove some inefficiencies from Wrapper for triggered objects --- include/wrapper/NonRealtime.hpp | 64 +++++++++++++++++++++----------- include/wrapper/RealTimeBase.hpp | 2 +- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/include/wrapper/NonRealtime.hpp b/include/wrapper/NonRealtime.hpp index 2e19d7a..20f7eac 100644 --- a/include/wrapper/NonRealtime.hpp +++ b/include/wrapper/NonRealtime.hpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace fluid { namespace client { @@ -46,7 +46,7 @@ namespace impl { using WeakCacheEntryPointer = std::weak_ptr; //could use weak_type in 17 public: - using Cache = std::map; + using Cache = std::unordered_map; static Cache mCache; private: static bool isNull(WeakCacheEntryPointer const& weak) { @@ -370,20 +370,23 @@ namespace impl { struct CommandProcess: public NRTCommand { - CommandProcess(World* world, sc_msg_iter* args, void* replyAddr): NRTCommand{world, args, replyAddr} + CommandProcess(World* world, sc_msg_iter* args, void* replyAddr): NRTCommand{world, args, replyAddr},mParams{Client::getParameterDescriptors()} { auto& ar = *args; if(auto ptr = get(NRTCommand::mID).lock()) { ptr->mDone = false; - ptr->mParams.template setParameterValuesRT(nullptr, world, ar); + mParams.template setParameterValuesRT(nullptr, world, ar); mSynchronous = static_cast(ar.geti()); } //if this fails, we'll hear about it in stage2 anyway } - explicit CommandProcess(index id,bool synchronous):NRTCommand{id},mSynchronous(synchronous) - {} + explicit CommandProcess(index id,bool synchronous,Params* params):NRTCommand{id},mSynchronous(synchronous), + mParams{Client::getParameterDescriptors()} + { + if(params) mParams = *params; + } static const char* name() @@ -396,9 +399,13 @@ namespace impl { { if(auto ptr = get(NRTCommand::mID).lock()) { + auto& params = ptr->mParams; + params = mParams; auto& client = ptr->mClient; + + // if(mOSCData) // { // params.template setParameterValuesRT(nullptr, world, *mOSCData); @@ -489,13 +496,14 @@ namespace impl { bool mSynchronous; size_t mCompletionMsgSize{0}; char* mCompletionMessage{nullptr}; + Params mParams; }; struct CommandProcessNew: public NRTCommand { CommandProcessNew(World* world, sc_msg_iter* args,void* replyAddr) : mNew{world, args, replyAddr}, - mProcess{mNew.mID,false} + mProcess{mNew.mID,false,nullptr} { mProcess.mSynchronous = args->geti(); mProcess.mReplyAddress = mNew.mReplyAddress; @@ -741,19 +749,20 @@ namespace impl { } NRTTriggerUnit() - : mControlsIterator{mInBuf + ControlOffset(),ControlSize()} + : mControlsIterator{mInBuf + ControlOffset(),ControlSize()},mParams{Client::getParameterDescriptors()} { mID = static_cast(mInBuf[0][0]); if(mID == -1) mID = count(); auto cmd = NonRealTime::rtalloc(mWorld,mID,mWorld, mControlsIterator, this); runAsyncCommand(mWorld, cmd, nullptr, 0, nullptr); + mInst = get(mID); set_calc_function(); Wrapper::getInterfaceTable()->fClearUnitOutputs(this, 1); } ~NRTTriggerUnit() { - if(auto ptr = get(mID).lock()) + if(auto ptr = mInst.lock()) { auto cmd = NonRealTime::rtalloc(mWorld,mID); runAsyncCommand(mWorld, cmd, nullptr, 0, nullptr); @@ -762,32 +771,39 @@ namespace impl { void next(int) { + + index triggerInput = static_cast(mInBuf[static_cast(mNumInputs) - 2][0]); mTrigger = mTrigger || triggerInput; - if(auto ptr = get(mID).lock()) - { - bool trigger = (!mPreviousTrigger) && mTrigger; - mPreviousTrigger = mTrigger; +// if(auto ptr = mInst->lock()) +// if(auto ptr = get(mID).lock()) +// { + bool trigger = (!mPreviousTrigger) && triggerInput;//mTrigger; + mPreviousTrigger = triggerInput; mTrigger = 0; - auto& client = ptr->mClient; +// auto& client = ptr->mClient; if(trigger) { mControlsIterator.reset(1 + mInBuf); //add one for ID - auto& params = ptr->mParams; - Wrapper::setParams(this,params,mControlsIterator,true,false); +// auto& params = ptr->mParams; + Wrapper::setParams(this,mParams,mControlsIterator,true,false); bool blocking = mInBuf[mNumInputs - 1][0] > 0; - CommandProcess* cmd = rtalloc(mWorld,mID,blocking); + CommandProcess* cmd = rtalloc(mWorld,mID,blocking,&mParams); runAsyncCommand(mWorld,cmd, nullptr,0, nullptr); mRunCount++; } else { - mDone = ptr->mDone; - out0(0) = mDone ? 1 : static_cast(client.progress()); + if(auto ptr = get(mID).lock()) + { + auto& client = ptr->mClient; + mDone = ptr->mDone; + out0(0) = mDone ? 1 : static_cast(client.progress()); + } } - } +// } // else printNotFound(id); } @@ -798,6 +814,8 @@ namespace impl { impl::FloatControlsIter mControlsIterator; index mID; index mRunCount{0}; + WeakCacheEntryPointer mInst; + Params mParams; }; struct NRTModelQueryUnit: SCUnit @@ -823,7 +841,8 @@ namespace impl { : mControls{mInBuf + ControlOffset(),ControlSize()} { index id = static_cast(in0(1)); - if(auto ptr = get(id).lock()) + mInst = get(id); + if(auto ptr = mInst.lock()) { auto& client = ptr->mClient; mDelegate.init(*this,client,mControls); @@ -835,7 +854,7 @@ namespace impl { void next(int) { index id = static_cast(in0(1)); - if(auto ptr = get(id).lock()) + if(auto ptr = mInst.lock()) { auto& client = ptr->mClient; auto& params = ptr->mParams; @@ -848,6 +867,7 @@ namespace impl { Delegate mDelegate; FloatControlsIter mControls; index mID; + WeakCacheEntryPointer mInst; }; diff --git a/include/wrapper/RealTimeBase.hpp b/include/wrapper/RealTimeBase.hpp index 88bcf3a..ab4e324 100644 --- a/include/wrapper/RealTimeBase.hpp +++ b/include/wrapper/RealTimeBase.hpp @@ -129,7 +129,7 @@ namespace impl{ mPrevTrig = trig; Wrapper::setParams(&unit, params, controls); - params.constrainParameterValues(); + params.constrainParameterValuesRT(nullptr); for (index i = 0; i < client.audioChannelsIn(); ++i) { From ed86083b996ac861e0bd7dd3b9e0ae40bba05ffb Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 6 Apr 2021 18:22:56 +0100 Subject: [PATCH 14/32] DataSetWr - corrected the help, with examples pointing at the 3 unexpected behaviours. --- .../HelpSource/Classes/FluidDataSetWr.schelp | 67 ++++++++++++++++--- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp index ad7dcc3..9da167b 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp @@ -4,12 +4,12 @@ categories:: FluidManipulation related:: Classes/FLuidDataSet DESCRIPTION:: -A UGen that adds labelled points to a link::Classes/FluidDataSet:: Internally, this calls code::setPoint::, so IDs that already exist will be overwritten, and new IDs will be added. The actual work is done on the server's command queue, rather than the real-thread. +A UGen that adds labelled points to a link::Classes/FluidDataSet:: Internally, this calls code::setPoint::, so IDs that already exist will be overwritten, and new IDs will be added. The actual work is done on the server's command queue, rather than the real-thread. -By default the object generates a numerical index that gets used for the point labels. This index starts counting from link::#offset#labelOffset:: and increments each time the Ugen is re-triggered with a zero to non-zero transition. The label is then concatenated with the code::idPrefix:: symbol, which is fixed at instantiation. In this way, one can make custom, incrementing labels, e.g. +By default the object takes a control input (code::idNumber::) as a numerical index that gets used for the point labels. This index is used to write each time the Ugen is re-triggered with a zero to non-zero transition. The label is then concatenated with the code::idPrefix:: symbol, which is fixed at instantiation. In this way, one can make custom, incrementing labels, e.g. code:: -FluidDataSetWr.kr(~somedataset,"my_data",0,~somebuffer,trig) +FluidDataSetWr.kr(~somedataset,"my_data",PulseCount.kr(trig),~somebuffer,trig) :: would add points like code::my_data0, mydata1, mydata2...:: if successively retriggered. @@ -27,11 +27,11 @@ ARGUMENT:: dataset An instance of link::Classes/FluidDataSet:: or an instance's name. ARGUMENT:: idPrefix -A string or symbol with a prefix for generated labels +A string or symbol with a prefix for generated labels. ARGUMENT:: idNumber ANCHOR::offset:: -An integer with the offset to start labeling from. If the UGen is run in a server-side loop (i.e. repeatedly re-triggered), the generated labels will count upwards from this offset. If < 0, then no numerical index will be applied to the generated label (i.e. only the labelPrefix is used). +An integer with the offset to start labeling from. If the UGen is run in a server-side loop (i.e. repeatedly re-triggered), the generated labels will count upwards from this offset. If nil, then no numerical index will be applied to the generated label (i.e. only the labelPrefix is used). ARGUMENT:: buf The link::Classes/Buffer:: containing the data point. @@ -48,11 +48,20 @@ EXAMPLES:: code:: s.reboot; -( ~ds = FluidDataSet(s); + +// write a single point, no counting +( +{ + var b = LocalBuf.newFrom([0,1,2,3]); + FreeSelfWhenDone.kr(FluidDataSetWr.kr(~ds,"help_data_point", idNumber: nil, buf:b)); +}.play(s); ) -//Write a 100 points whose values increase +~ds.print; +~ds.clear + +//Write a 100 points as fast as possible - NOT WORKING (not getting 0, then 1 2 3 4 are the same values) ( ~ds.clear; OSCFunc({ @@ -64,12 +73,52 @@ OSCFunc({ var b = LocalBuf.newFrom([0,1,2,3]); var trig = Impulse.kr(ControlRate.ir / 2); var idx = Stepper.kr(trig,min:0,max:n); - 4.collect{|i| BufWr.kr([(4 * idx) + i],b,i)}; + 4.collect{|i| BufWr.kr([(4 * idx) + i],b,i)}; FluidDataSetWr.kr(~ds,idNumber:idx,buf:b,trig:trig); SendReply.kr(idx >= n, '/datasetwrdone'); FreeSelf.kr(idx >= n); - }.play(s,args:[n:100]); ) +~ds.print; +~ds.clear + +// incremental buffer writing +( +{ + var buf = LocalBuf.newFrom([0,1,2,3]); + var noise = 4.collect{WhiteNoise.kr()}; + var trig = Impulse.kr(2); + var count = PulseCount.kr(trig); + 4.do{|i| + BufWr.kr(noise[i], buf, DC.kr(i)); + }; + FluidDataSetWr.kr(~ds, idNumber: count, trig: trig, buf:buf); +}.play(s); +) + +//print a few times (NOT WORKING - not getting the 0) +~ds.print; + +//clear before flushing the writing synth to enjoy the behaviour +~ds.clear +~ds.print; + +// circular writing +( +{ + var buf = LocalBuf.newFrom([0,1,2,3]); + var noise = 4.collect{WhiteNoise.kr()}; + var trig = Impulse.kr(2); + var count = Stepper.kr(trig, max: 10).poll; + 4.do{|i| + BufWr.kr(noise[i], buf, DC.kr(i)); + }; + FluidDataSetWr.kr(~ds, idNumber: count, trig: trig, buf:buf); +}.play(s); +) + +~ds.print; //NOT WORKING - after one run around, sidNumber is multiplied buy 10! +~ds.clear + :: From 1e4030999a141a1ee25f8732201d462d10b1a1f5 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 6 Apr 2021 20:14:31 +0100 Subject: [PATCH 15/32] Fix FluidDataSetWr: stringstr doesn't reset as hoped, use std::string instead --- include/clients/rt/FluidDataSetWr.hpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/include/clients/rt/FluidDataSetWr.hpp b/include/clients/rt/FluidDataSetWr.hpp index ab13df0..e41e867 100644 --- a/include/clients/rt/FluidDataSetWr.hpp +++ b/include/clients/rt/FluidDataSetWr.hpp @@ -43,22 +43,16 @@ public: if (idPrefix.size() == 0 && idNumberArr[0] == 0) return {Result::Status::kError, "No ID supplied"}; - mStream.clear(); - mStream.seekp(0); - - mStream << idPrefix; + std::string id = idPrefix; if (idNumberArr[0] > 0) - mStream << idNumberArr[1]; + id += std::to_string(idNumberArr[1]); auto buf = get(); - return datasetPtr->setPoint(mStream.str(), buf); + return datasetPtr->setPoint(id, buf); } else return {Result::Status::kError, "No DataSet"}; } - -private: - std::ostringstream mStream; }; using NRTThreadedDataSetWriter = From 8f1f1adc6325adb6b8b3a373b18f9ca67dc6eda1 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 6 Apr 2021 22:31:59 +0100 Subject: [PATCH 16/32] Fix FluidDataSetWr.schelp: adjust control rate down for first example. Use stepper throuought --- .../HelpSource/Classes/FluidDataSetWr.schelp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp index 9da167b..da14798 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp @@ -58,6 +58,7 @@ s.reboot; }.play(s); ) + ~ds.print; ~ds.clear @@ -71,12 +72,12 @@ OSCFunc({ { |n| var b = LocalBuf.newFrom([0,1,2,3]); - var trig = Impulse.kr(ControlRate.ir / 2); - var idx = Stepper.kr(trig,min:0,max:n); + var trig = Impulse.kr(ControlRate.ir / 8); + var idx = Stepper.kr(trig,min:-1, max:n); 4.collect{|i| BufWr.kr([(4 * idx) + i],b,i)}; FluidDataSetWr.kr(~ds,idNumber:idx,buf:b,trig:trig); - SendReply.kr(idx >= n, '/datasetwrdone'); - FreeSelf.kr(idx >= n); + SendReply.kr(idx >= (n-1), '/datasetwrdone'); + FreeSelf.kr(idx >= (n-1)); }.play(s,args:[n:100]); ) @@ -89,7 +90,7 @@ OSCFunc({ var buf = LocalBuf.newFrom([0,1,2,3]); var noise = 4.collect{WhiteNoise.kr()}; var trig = Impulse.kr(2); - var count = PulseCount.kr(trig); + var count = Stepper.kr(trig,min:0); 4.do{|i| BufWr.kr(noise[i], buf, DC.kr(i)); }; From 927d60dfcc4686f4869e66204047756003f417b7 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 7 Apr 2021 09:55:08 +0100 Subject: [PATCH 17/32] last typo and more verbose examples to DataSetWr --- .../HelpSource/Classes/FluidDataSetWr.schelp | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp index da14798..dd1c27e 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp @@ -62,7 +62,7 @@ s.reboot; ~ds.print; ~ds.clear -//Write a 100 points as fast as possible - NOT WORKING (not getting 0, then 1 2 3 4 are the same values) +//Write a 100 points quite fast with server-side triggering ( ~ds.clear; OSCFunc({ @@ -73,7 +73,7 @@ OSCFunc({ { |n| var b = LocalBuf.newFrom([0,1,2,3]); var trig = Impulse.kr(ControlRate.ir / 8); - var idx = Stepper.kr(trig,min:-1, max:n); + var idx = Stepper.kr(trig,min:-1, max:n); //we need to start at -1 to catch the first increment 4.collect{|i| BufWr.kr([(4 * idx) + i],b,i)}; FluidDataSetWr.kr(~ds,idNumber:idx,buf:b,trig:trig); SendReply.kr(idx >= (n-1), '/datasetwrdone'); @@ -84,13 +84,37 @@ OSCFunc({ ~ds.print; ~ds.clear -// incremental buffer writing +//Again, but as fast as possible using a feedback of the trigger we are given when the writing is done +( +~ds.clear; +OSCFunc({ + "FluidDataSetWr help: all points written".postln; + ~ds.print +},'/datasetwrdone').oneShot; + +{ |n| + var b = LocalBuf.newFrom([0,1,2,3]); + var trig = LocalIn.kr(1,1); + var idx = Stepper.kr(trig,min:-1, max:n); + var wr = FluidDataSetWr.kr(~ds,idNumber:idx,buf:b,trig:trig); + 4.collect{|i| BufWr.kr([(4 * idx) + i],b,i)}; + LocalOut.kr(Done.kr(wr)); + SendReply.kr(idx >= (n-1), '/datasetwrdone'); + FreeSelf.kr(idx >= (n-1)); +}.play(s,args:[n:100]); +) + +~ds.print; +~ds.clear + +// incremental buffer writing - sky is the limit +// start the entry maker, trigging twice a second ( { var buf = LocalBuf.newFrom([0,1,2,3]); var noise = 4.collect{WhiteNoise.kr()}; var trig = Impulse.kr(2); - var count = Stepper.kr(trig,min:0); + var count = PulseCount.kr(trig,); 4.do{|i| BufWr.kr(noise[i], buf, DC.kr(i)); }; @@ -98,10 +122,10 @@ OSCFunc({ }.play(s); ) -//print a few times (NOT WORKING - not getting the 0) +//print a few times ~ds.print; -//clear before flushing the writing synth to enjoy the behaviour +//clear before flushing the writing synth ~ds.clear ~ds.print; @@ -111,7 +135,7 @@ OSCFunc({ var buf = LocalBuf.newFrom([0,1,2,3]); var noise = 4.collect{WhiteNoise.kr()}; var trig = Impulse.kr(2); - var count = Stepper.kr(trig, max: 10).poll; + var count = Stepper.kr(trig, min: 0, max: 9, resetval: -1); //0 to 9, starting at -1 to catch the first entry 4.do{|i| BufWr.kr(noise[i], buf, DC.kr(i)); }; @@ -119,7 +143,7 @@ OSCFunc({ }.play(s); ) -~ds.print; //NOT WORKING - after one run around, sidNumber is multiplied buy 10! +~ds.print; ~ds.clear :: From 45a7fa8be66d869afc701a5807acca73cedfdec6 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Wed, 7 Apr 2021 11:00:51 +0100 Subject: [PATCH 18/32] Fix accidental param overwrite in processNew scenarios --- include/wrapper/NonRealtime.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/wrapper/NonRealtime.hpp b/include/wrapper/NonRealtime.hpp index 20f7eac..9983c5a 100644 --- a/include/wrapper/NonRealtime.hpp +++ b/include/wrapper/NonRealtime.hpp @@ -385,7 +385,11 @@ namespace impl { explicit CommandProcess(index id,bool synchronous,Params* params):NRTCommand{id},mSynchronous(synchronous), mParams{Client::getParameterDescriptors()} { - if(params) mParams = *params; + if(params) + { + mParams = *params; + mOverwriteParams = true; + } } @@ -401,7 +405,7 @@ namespace impl { { auto& params = ptr->mParams; - params = mParams; + if(mOverwriteParams) params = mParams; auto& client = ptr->mClient; @@ -497,6 +501,7 @@ namespace impl { size_t mCompletionMsgSize{0}; char* mCompletionMessage{nullptr}; Params mParams; + bool mOverwriteParams{false}; }; struct CommandProcessNew: public NRTCommand From e18e8221ed9470432fb49388fbe2584b48ad178a Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 7 Apr 2021 13:51:53 +0100 Subject: [PATCH 19/32] descriptors: new interface with padding, and explanation --- release-packaging/Classes/FluidBufMFCC.sc | 24 ++++++++-------- release-packaging/Classes/FluidBufMelBands.sc | 12 ++++---- release-packaging/Classes/FluidBufPitch.sc | 28 +++++++++---------- release-packaging/Classes/FluidBufSTFT.sc | 12 ++++---- .../Classes/FluidBufSpectralShape.sc | 12 ++++---- .../HelpSource/Classes/FluidBufMFCC.schelp | 5 +++- .../Classes/FluidBufMelBands.schelp | 3 ++ .../HelpSource/Classes/FluidBufPitch.schelp | 9 ++++-- .../HelpSource/Classes/FluidBufSTFT.schelp | 6 ++-- .../Classes/FluidBufSpectralShape.schelp | 5 +++- 10 files changed, 64 insertions(+), 52 deletions(-) diff --git a/release-packaging/Classes/FluidBufMFCC.sc b/release-packaging/Classes/FluidBufMFCC.sc index 0d6360e..8e371e9 100644 --- a/release-packaging/Classes/FluidBufMFCC.sc +++ b/release-packaging/Classes/FluidBufMFCC.sc @@ -1,45 +1,45 @@ FluidBufMFCC : FluidBufProcessor{ - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0| - + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0| + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; features = features.asUGenInput; source.isNil.if {"FluidBufMFCC: Invalid source buffer".throw}; features.isNil.if {"FluidBufMFCC: Invalid features buffer".throw}; - - ^FluidProxyUgen.kr(\FluidBufMFCCTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq,numCoeffs, windowSize, hopSize, fftSize, maxFFTSize,trig, blocking); + + ^FluidProxyUgen.kr(\FluidBufMFCCTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, numCoeffs, numBands, minFreq, maxFreq,numCoeffs, windowSize, hopSize, fftSize, maxFFTSize,trig, blocking); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone=true, action | - + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone=true, action | + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; features = features.asUGenInput; source.isNil.if {"FluidBufMFCC: Invalid source buffer".throw}; features.isNil.if {"FluidBufMFCC: Invalid features buffer".throw}; - + ^this.new( server, nil,[features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq, numCoeffs,windowSize, hopSize, fftSize,maxFFTSize,0],freeWhenDone,action + [source, startFrame, numFrames, startChan, numChans, features, padding, numCoeffs, numBands, minFreq, maxFreq, numCoeffs,windowSize, hopSize, fftSize, maxFFTSize,0],freeWhenDone,action ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone=true, action | - + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numCoeffs = 13, numBands = 40, minFreq = 20, maxFreq = 20000, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone=true, action | + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; features = features.asUGenInput; source.isNil.if {"FluidBufMFCC: Invalid source buffer".throw}; features.isNil.if {"FluidBufMFCC: Invalid features buffer".throw}; - + ^this.new( server, nil,[features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, numCoeffs, numBands, minFreq, maxFreq,numCoeffs, windowSize, hopSize, fftSize,maxFFTSize,1],freeWhenDone,action + [source, startFrame, numFrames, startChan, numChans, features, padding, numCoeffs, numBands, minFreq, maxFreq,numCoeffs, windowSize, hopSize, fftSize, maxFFTSize,1],freeWhenDone,action ); } } diff --git a/release-packaging/Classes/FluidBufMelBands.sc b/release-packaging/Classes/FluidBufMelBands.sc index cb5eb12..b11ffb7 100644 --- a/release-packaging/Classes/FluidBufMelBands.sc +++ b/release-packaging/Classes/FluidBufMelBands.sc @@ -1,6 +1,6 @@ FluidBufMelBands : FluidBufProcessor { - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0| + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0| var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -11,10 +11,10 @@ FluidBufMelBands : FluidBufProcessor { features.isNil.if {"FluidBufMelBands: Invalid features buffer".throw}; - ^FluidProxyUgen.kr(\FluidBufMelBandsTrigger,-1, source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize,maxFFTSize, trig, blocking); + ^FluidProxyUgen.kr(\FluidBufMelBandsTrigger,-1, source, startFrame, numFrames, startChan, numChans, features, padding, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action| + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -27,11 +27,11 @@ FluidBufMelBands : FluidBufProcessor { ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize,maxFFTSize,0],freeWhenDone,action + [source, startFrame, numFrames, startChan, numChans, features, padding, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize, maxFFTSize, 0],freeWhenDone,action ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action| + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, numBands = 40, minFreq = 20, maxFreq = 20000, normalize = 1, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -44,7 +44,7 @@ FluidBufMelBands : FluidBufProcessor { ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize,maxFFTSize,1],freeWhenDone,action + [source, startFrame, numFrames, startChan, numChans, features, padding, numBands, minFreq, maxFreq, numBands, normalize, windowSize, hopSize, fftSize, maxFFTSize, 1],freeWhenDone,action ); } } diff --git a/release-packaging/Classes/FluidBufPitch.sc b/release-packaging/Classes/FluidBufPitch.sc index 608a404..d62190b 100644 --- a/release-packaging/Classes/FluidBufPitch.sc +++ b/release-packaging/Classes/FluidBufPitch.sc @@ -1,21 +1,21 @@ FluidBufPitch : FluidBufProcessor{ - - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0| - + + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0| + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; features = features.asUGenInput; source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; - features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; - - ^FluidProxyUgen.kr(\FluidBufPitchTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking); + features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; + + ^FluidProxyUgen.kr(\FluidBufPitchTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action| - + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; @@ -23,16 +23,16 @@ FluidBufPitch : FluidBufProcessor{ source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; - + ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone, action + [source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone, action ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action| - + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, algorithm = 2, minFreq = 20, maxFreq = 10000, unit = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| + var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; source = source.asUGenInput; @@ -40,11 +40,11 @@ FluidBufPitch : FluidBufProcessor{ source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; - + ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone, action + [source, startFrame, numFrames, startChan, numChans, features, padding, algorithm, minFreq, maxFreq, unit, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone, action ); } } diff --git a/release-packaging/Classes/FluidBufSTFT.sc b/release-packaging/Classes/FluidBufSTFT.sc index bd0eb2d..e93d206 100644 --- a/release-packaging/Classes/FluidBufSTFT.sc +++ b/release-packaging/Classes/FluidBufSTFT.sc @@ -1,6 +1,6 @@ FluidBufSTFT : FluidBufProcessor { - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0,windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 1| + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0,windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 1| // source = source.asUGenInput; @@ -10,10 +10,10 @@ FluidBufSTFT : FluidBufProcessor { phase = phase ? -1; resynthesis = resynthesis ? - 1; - ^FluidProxyUgen.kr(\FluidBufSTFTTrigger, -1, source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, windowSize, hopSize, fftSize,trig, blocking); + ^FluidProxyUgen.kr(\FluidBufSTFTTrigger, -1, source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, padding, windowSize, hopSize, fftSize, trig, blocking); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| // source = source.asUGenInput; @@ -26,11 +26,11 @@ FluidBufSTFT : FluidBufProcessor { ^this.new( server, nil, [magnitude,phase,resynthesis].select{|b| b != -1} ).processList( - [source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, windowSize, hopSize, fftSize, 0], freeWhenDone, action + [source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, padding, windowSize, hopSize, fftSize, 0], freeWhenDone, action ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1,freeWhenDone = true, action| // source = source.asUGenInput; source = source ? -1; @@ -41,7 +41,7 @@ FluidBufSTFT : FluidBufProcessor { ^this.new( server, nil, [magnitude,phase,resynthesis].select{|b| b != -1} ).processList( - [source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, windowSize, hopSize, fftSize,1], freeWhenDone, action + [source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, padding, windowSize, hopSize, fftSize, 1], freeWhenDone, action ); } } diff --git a/release-packaging/Classes/FluidBufSpectralShape.sc b/release-packaging/Classes/FluidBufSpectralShape.sc index 4a28417..b4bb4ab 100644 --- a/release-packaging/Classes/FluidBufSpectralShape.sc +++ b/release-packaging/Classes/FluidBufSpectralShape.sc @@ -4,7 +4,7 @@ FluidBufSpectralShape : FluidBufProcessor { ^\FluidBufSpecShp } - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 0| + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, trig = 1, blocking = 0| var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -14,11 +14,11 @@ FluidBufSpectralShape : FluidBufProcessor { source.isNil.if {"FluidBufSpectralShape: Invalid source buffer".throw}; features.isNil.if {"FluidBufSpectralShape: Invalid features buffer".throw}; - ^FluidProxyUgen.kr(this.objectClassName++\Trigger, -1, source, startFrame, numFrames, startChan, numChans, features, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking); + ^FluidProxyUgen.kr(this.objectClassName++\Trigger, -1, source, startFrame, numFrames, startChan, numChans, features, padding, windowSize, hopSize, fftSize, maxFFTSize, trig, blocking); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action| + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -31,11 +31,11 @@ FluidBufSpectralShape : FluidBufProcessor { ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone, action + [source, startFrame, numFrames, startChan, numChans, features, padding, windowSize, hopSize, fftSize, maxFFTSize, 0], freeWhenDone, action ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, windowSize = 1024, hopSize = -1, fftSize = -1, freeWhenDone = true, action| + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, windowSize = 1024, hopSize = -1, fftSize = -1, padding = 1, freeWhenDone = true, action| var maxFFTSize = if (fftSize == -1) {windowSize.nextPowerOfTwo} {fftSize}; @@ -48,7 +48,7 @@ FluidBufSpectralShape : FluidBufProcessor { ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone, action + [source, startFrame, numFrames, startChan, numChans, features, padding, windowSize, hopSize, fftSize, maxFFTSize, 1], freeWhenDone, action ); } } diff --git a/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp b/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp index 8ad8c8a..bfc4358 100644 --- a/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp @@ -59,8 +59,11 @@ ARGUMENT:: hopSize ARGUMENT:: fftSize The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. +ARGUMENT:: padding + The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. + ARGUMENT:: freeWhenDone -Free the server instance when processing complete. Default true + Free the server instance when processing complete. Default true ARGUMENT:: action A Function to be evaluated once the offline process has finished and all Buffer's instance variables have been updated on the client side. The function will be passed [features] as an argument. diff --git a/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp b/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp index 8b76900..e71a189 100644 --- a/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp @@ -60,6 +60,9 @@ ARGUMENT:: hopSize ARGUMENT:: fftSize The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. +ARGUMENT:: padding + The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. + ARGUMENT:: freeWhenDone Free the server instance when processing complete. Default true diff --git a/release-packaging/HelpSource/Classes/FluidBufPitch.schelp b/release-packaging/HelpSource/Classes/FluidBufPitch.schelp index 99cb9d8..7eed7a7 100644 --- a/release-packaging/HelpSource/Classes/FluidBufPitch.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufPitch.schelp @@ -65,8 +65,11 @@ ARGUMENT:: hopSize ARGUMENT:: fftSize The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. +ARGUMENT:: padding + The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. + ARGUMENT:: freeWhenDone -Free the server instance when processing complete. Default true + Free the server instance when processing complete. Default true ARGUMENT:: action A Function to be evaluated once the offline process has finished and all Buffer's instance variables have been updated on the client side. The function will be passed [features] as an argument. @@ -164,8 +167,8 @@ d.do({ e.postln; //granulate only the frames that are in our buffer -// We need to convert our indices to frame start. Their position was (index * hopSize) - (windowSize) in FluidBufPitch -f = e.collect({arg i; (i * 512) - 1024}); +// We need to convert our indices to frame start. Their position was (index * hopSize) - (hopSize) in FluidBufPitch +f = e.collect({arg i; (i * 512) - 512}); // define a basic grain synth ( diff --git a/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp b/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp index f86fcff..b2e1a79 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp @@ -53,6 +53,9 @@ How many samples there are in-between analysis windows. The -1 default value wil ARGUMENT:: fftSize The FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. For this object it is effectively capped at 65536. +ARGUMENT:: padding +The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. + ARGUMENT:: freeWhenDone Free the server instance when processing complete. Default true @@ -81,9 +84,6 @@ fork{ } ) -FluidBufSTFT.process(s,source:b,magnitude:m,phase:p) -m.getn(4444,10,{|x|x.postln;}) - { PlayBuf.ar(1,r); }.play //nullsum diff --git a/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp b/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp index 4f49ccd..f2e3874 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp @@ -64,8 +64,11 @@ ARGUMENT:: hopSize ARGUMENT:: fftSize The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. +ARGUMENT:: padding + The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. + ARGUMENT:: freeWhenDone -Free the server instance when processing complete. Default true + Free the server instance when processing complete. Default true ARGUMENT:: action A Function to be evaluated once the offline process has finished and all Buffer's instance variables have been updated on the client side. The function will be passed [features] as an argument. From c6cd158f533ccdb3784b873ba382f4c15511abfb Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 7 Apr 2021 13:55:32 +0100 Subject: [PATCH 20/32] padding def now in proper English (thanks @owen) --- release-packaging/HelpSource/Classes/FluidBufMFCC.schelp | 2 +- release-packaging/HelpSource/Classes/FluidBufMelBands.schelp | 2 +- release-packaging/HelpSource/Classes/FluidBufPitch.schelp | 2 +- release-packaging/HelpSource/Classes/FluidBufSTFT.schelp | 2 +- .../HelpSource/Classes/FluidBufSpectralShape.schelp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp b/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp index bfc4358..9bc9764 100644 --- a/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufMFCC.schelp @@ -60,7 +60,7 @@ ARGUMENT:: fftSize The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. ARGUMENT:: padding - The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. + Controls the zero-padding added to either end of the source buffer or segment. Possible values are 0 (no padding), 1 (default, half the window size), or 2 (window size - hop size). Padding ensures that all input samples are completely analysed: with no padding, the first analysis window starts at time 0, and the samples at either end will be tapered by the STFT windowing function. Mode 1 has the effect of centering the first sample in the analysis window and ensuring that the very start and end of the segment are accounted for in the analysis. Mode 2 can be useful when the overlap factor (window size / hop size) is greater than 2, to ensure that the input samples at either end of the segment are covered by the same number of analysis frames as the rest of the analysed material. ARGUMENT:: freeWhenDone Free the server instance when processing complete. Default true diff --git a/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp b/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp index e71a189..9d15d33 100644 --- a/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufMelBands.schelp @@ -61,7 +61,7 @@ ARGUMENT:: fftSize The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. ARGUMENT:: padding - The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. + Controls the zero-padding added to either end of the source buffer or segment. Possible values are 0 (no padding), 1 (default, half the window size), or 2 (window size - hop size). Padding ensures that all input samples are completely analysed: with no padding, the first analysis window starts at time 0, and the samples at either end will be tapered by the STFT windowing function. Mode 1 has the effect of centering the first sample in the analysis window and ensuring that the very start and end of the segment are accounted for in the analysis. Mode 2 can be useful when the overlap factor (window size / hop size) is greater than 2, to ensure that the input samples at either end of the segment are covered by the same number of analysis frames as the rest of the analysed material. ARGUMENT:: freeWhenDone Free the server instance when processing complete. Default true diff --git a/release-packaging/HelpSource/Classes/FluidBufPitch.schelp b/release-packaging/HelpSource/Classes/FluidBufPitch.schelp index 7eed7a7..f2352ea 100644 --- a/release-packaging/HelpSource/Classes/FluidBufPitch.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufPitch.schelp @@ -66,7 +66,7 @@ ARGUMENT:: fftSize The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. ARGUMENT:: padding - The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. + Controls the zero-padding added to either end of the source buffer or segment. Possible values are 0 (no padding), 1 (default, half the window size), or 2 (window size - hop size). Padding ensures that all input samples are completely analysed: with no padding, the first analysis window starts at time 0, and the samples at either end will be tapered by the STFT windowing function. Mode 1 has the effect of centering the first sample in the analysis window and ensuring that the very start and end of the segment are accounted for in the analysis. Mode 2 can be useful when the overlap factor (window size / hop size) is greater than 2, to ensure that the input samples at either end of the segment are covered by the same number of analysis frames as the rest of the analysed material. ARGUMENT:: freeWhenDone Free the server instance when processing complete. Default true diff --git a/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp b/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp index b2e1a79..aa7ee28 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp @@ -54,7 +54,7 @@ ARGUMENT:: fftSize The FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. For this object it is effectively capped at 65536. ARGUMENT:: padding -The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. +Controls the zero-padding added to either end of the source buffer or segment. Possible values are 0 (no padding), 1 (default, half the window size), or 2 (window size - hop size). Padding ensures that all input samples are completely analysed: with no padding, the first analysis window starts at time 0, and the samples at either end will be tapered by the STFT windowing function. Mode 1 has the effect of centering the first sample in the analysis window and ensuring that the very start and end of the segment are accounted for in the analysis. Mode 2 can be useful when the overlap factor (window size / hop size) is greater than 2, to ensure that the input samples at either end of the segment are covered by the same number of analysis frames as the rest of the analysed material. ARGUMENT:: freeWhenDone Free the server instance when processing complete. Default true diff --git a/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp b/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp index f2e3874..9561cc6 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSpectralShape.schelp @@ -65,7 +65,7 @@ ARGUMENT:: fftSize The inner FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. ARGUMENT:: padding - The padding applied to both sides of the input buffer. By default (1) it is half the windowSize to ensure that the beginning of the audio is centered on the window and that no audio is left untouched at the end. (2) will apply (windowSize - hopSize) to cover each sides by the same number of overlaps. (0) will disable and start from the beginning, with the windowing effectively scaling down the first samples. +Controls the zero-padding added to either end of the source buffer or segment. Possible values are 0 (no padding), 1 (default, half the window size), or 2 (window size - hop size). Padding ensures that all input samples are completely analysed: with no padding, the first analysis window starts at time 0, and the samples at either end will be tapered by the STFT windowing function. Mode 1 has the effect of centering the first sample in the analysis window and ensuring that the very start and end of the segment are accounted for in the analysis. Mode 2 can be useful when the overlap factor (window size / hop size) is greater than 2, to ensure that the input samples at either end of the segment are covered by the same number of analysis frames as the rest of the analysed material. ARGUMENT:: freeWhenDone Free the server instance when processing complete. Default true From 50af1fefd53af52255658ce45bc50681c474f785 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Sun, 11 Apr 2021 00:48:54 +0100 Subject: [PATCH 21/32] Expand Macros, Fix Repetition: DataSetWr --- include/clients/rt/FluidDataSetWr.hpp | 35 ++++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/include/clients/rt/FluidDataSetWr.hpp b/include/clients/rt/FluidDataSetWr.hpp index e41e867..028fcd4 100644 --- a/include/clients/rt/FluidDataSetWr.hpp +++ b/include/clients/rt/FluidDataSetWr.hpp @@ -19,17 +19,33 @@ namespace fluid { namespace client { +namespace datasetwr { + +enum { kDataSet, kIDPrefix, kIDNumber, kBuffer }; + +constexpr std::initializer_list idNumberDefaults{0, 0}; + +constexpr auto DataSetWrParams = defineParameters( + DataSetClientRef::makeParam("dataSet", "DataSet ID"), + StringParam("idPrefix", "ID Prefix"), + LongArrayParam("idNumber", "ID Counter Offset", idNumberDefaults), + BufferParam("buf", "Data Buffer")); class DataSetWriterClient : public FluidBaseClient, OfflineIn, OfflineOut { - enum { kDataSet, kIDPrefix, kIDNumber, kBuffer }; - static constexpr std::initializer_list idNumberDefaults{0, 0}; public: - FLUID_DECLARE_PARAMS(DataSetClientRef::makeParam("dataSet", "DataSet ID"), - StringParam("idPrefix", "ID Prefix"), - LongArrayParam("idNumber", "ID Counter Offset", - idNumberDefaults), - BufferParam("buf", "Data Buffer")); + using ParamDescType = decltype(DataSetWrParams); + + using ParamSetViewType = ParameterSetView; + std::reference_wrapper mParams; + + void setParams(ParamSetViewType &p) { mParams = p; } + + template auto &get() const { + return mParams.get().template get(); + } + + static constexpr auto &getParameterDescriptors() { return DataSetWrParams; } DataSetWriterClient(ParamSetViewType &p) : mParams(p) {} @@ -43,7 +59,7 @@ public: if (idPrefix.size() == 0 && idNumberArr[0] == 0) return {Result::Status::kError, "No ID supplied"}; - std::string id = idPrefix; + std::string id = idPrefix; if (idNumberArr[0] > 0) id += std::to_string(idNumberArr[1]); @@ -54,8 +70,9 @@ public: return {Result::Status::kError, "No DataSet"}; } }; +} // namespace datasetwr using NRTThreadedDataSetWriter = - NRTThreadingAdaptor>; + NRTThreadingAdaptor>; } // namespace client } // namespace fluid From 9ab48a6def0fd55bf488291805a3f33e4021bffa Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Mon, 12 Apr 2021 08:58:04 +0100 Subject: [PATCH 22/32] add getIds to dataset (and correct help) --- .../HelpSource/Classes/FluidDataSet.schelp | 11 ++++++++++- .../HelpSource/Classes/FluidDataSetWr.schelp | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidDataSet.schelp b/release-packaging/HelpSource/Classes/FluidDataSet.schelp index b28cbaf..6643181 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSet.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSet.schelp @@ -77,7 +77,16 @@ The link::Classes/FluidLabelSet:: from which to retrieve the point's IDs associa ARGUMENT:: action A function to run when the import is done. + +METHOD:: getIds +Export to the dataset IDs to a link::Classes/FluidLabelSet::. + +ARGUMENT:: labelSet +The link::Classes/FluidLabelSet:: to export to. Its content will be replaced. ​ +ARGUMENT:: action +A function to run when the export is done. + METHOD:: merge Merge sourceDataSet in the current DataSet. It will update the value of points with the same label if overwrite is set to 1. To add columns instead, see the 'transformJoin' method of link::Classes/FluidDataSetQuery:: @@ -136,7 +145,7 @@ fork{ var count = PulseCount.kr(trig) - 1; var buf = LocalBuf(1); BufWr.kr(count, buf); - FluidDataSetWr.kr(~ds.asUGenInput, buf: buf, trig: trig); + FluidDataSetWr.kr(~ds.asUGenInput, idNumber: count, buf: buf, trig: trig); FreeSelf.kr(count - 8); }.play.onFree{~ds.dump{|o| o.postln;~ds.free}} ) diff --git a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp index dd1c27e..f92de08 100644 --- a/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp +++ b/release-packaging/HelpSource/Classes/FluidDataSetWr.schelp @@ -114,7 +114,7 @@ OSCFunc({ var buf = LocalBuf.newFrom([0,1,2,3]); var noise = 4.collect{WhiteNoise.kr()}; var trig = Impulse.kr(2); - var count = PulseCount.kr(trig,); + var count = PulseCount.kr(trig); 4.do{|i| BufWr.kr(noise[i], buf, DC.kr(i)); }; From 7d09d83f4fbaa35c59a4b15d296d7eacc951d6c2 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Mon, 12 Apr 2021 09:38:50 +0100 Subject: [PATCH 23/32] all examples with DataSetWr have the right counting/bypassing now --- .../0-demo-dataset-maker-utilities.scd | 4 ++-- .../10a-weighted-MFCCs-comparison.scd | 22 +++++++++---------- .../11-compositing-datasets.scd | 6 ++--- .../12-windowed-clustered-segmentation.scd | 4 ++-- .../8c-mlp-regressor-as-dim-redux.scd | 2 +- .../HelpSource/Classes/FluidMDS.schelp | 4 ++-- .../HelpSource/Classes/FluidNormalize.schelp | 2 +- .../HelpSource/Classes/FluidPCA.schelp | 4 ++-- .../Classes/FluidProcessSlices.schelp | 4 ++-- .../Classes/FluidRobustScale.schelp | 2 +- .../Classes/FluidStandardize.schelp | 2 +- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/release-packaging/Examples/dataset/0-demo-dataset-maker-utilities.scd b/release-packaging/Examples/dataset/0-demo-dataset-maker-utilities.scd index 9ceb017..d07a730 100644 --- a/release-packaging/Examples/dataset/0-demo-dataset-maker-utilities.scd +++ b/release-packaging/Examples/dataset/0-demo-dataset-maker-utilities.scd @@ -23,7 +23,7 @@ mfcc = FluidBufMFCC.kr(src, startFrame:start, numFrames:num, numChans:1, features:~mfccbuf[voice], trig:1, blocking: 1); stats = FluidBufStats.kr(~mfccbuf[voice], stats:~statsbuf[voice], trig:Done.kr(mfcc), blocking: 1); flatten = FluidBufFlatten.kr(~statsbuf[voice], ~flatbuf[voice], trig:Done.kr(stats), blocking: 1); - writer = FluidDataSetWr.kr(~ds, label, -1, ~flatbuf[voice], trig: Done.kr(flatten), blocking: 1) + writer = FluidDataSetWr.kr(~ds, label, nil, ~flatbuf[voice], trig: Done.kr(flatten), blocking: 1) }); ) @@ -166,4 +166,4 @@ Routine{ dur.wait; }; }.play; -) \ No newline at end of file +) diff --git a/release-packaging/Examples/dataset/1-learning examples/10a-weighted-MFCCs-comparison.scd b/release-packaging/Examples/dataset/1-learning examples/10a-weighted-MFCCs-comparison.scd index 8ed2aa0..ae629df 100644 --- a/release-packaging/Examples/dataset/1-learning examples/10a-weighted-MFCCs-comparison.scd +++ b/release-packaging/Examples/dataset/1-learning examples/10a-weighted-MFCCs-comparison.scd @@ -23,10 +23,10 @@ var label, voice, mfcc, stats, flatten; label = data.key; voice = data.value[\voice]; - mfcc = FluidBufMFCC.kr(src,startFrame:start,numFrames:num,numChans:1,features:~mfccbuf[voice],trig:1,blocking: 1); + mfcc = FluidBufMFCC.kr(src, startFrame:start, numFrames:num, numChans:1, features:~mfccbuf[voice], padding: 2, trig:1, blocking: 1); stats = FluidBufStats.kr(~mfccbuf[voice], stats:~statsbuf[voice], numDerivs: 1, trig:Done.kr(mfcc), blocking: 1); - flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1); - FluidDataSetWr.kr(~ds,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1); + flatten = FluidBufFlatten.kr(~statsbuf[voice], ~flatbuf[voice], trig:Done.kr(stats), blocking: 1); + FluidDataSetWr.kr(~ds, label, nil, ~flatbuf[voice], Done.kr(flatten), blocking: 1); }); // here we make another processor, this time with doing an amplitude weighing @@ -34,12 +34,12 @@ var label, voice, loud, weights, mfcc, stats, flatten; label = data.key; voice = data.value[\voice]; - mfcc = FluidBufMFCC.kr(src,startFrame:start,numFrames:num,numChans:1,features:~mfccbuf[voice],trig:1,blocking: 1); - loud = FluidBufLoudness.kr(src,startFrame:start,numFrames:num,numChans:1,features:~loudbuf[voice],trig:Done.kr(mfcc),blocking: 1); - weights = FluidBufScale.kr(~loudbuf[voice],numChans: 1,destination: ~weightbuf[voice],inputLow: -70,inputHigh: 0, trig: Done.kr(loud),blocking: 1); + mfcc = FluidBufMFCC.kr(src, startFrame:start, numFrames:num, numChans:1, features:~mfccbuf[voice], padding: 2, trig:1, blocking: 1); + loud = FluidBufLoudness.kr(src, startFrame:start, numFrames:num, numChans:1, features:~loudbuf[voice], trig:Done.kr(mfcc), blocking: 1); + weights = FluidBufScale.kr(~loudbuf[voice], numChans: 1, destination: ~weightbuf[voice], inputLow: -70, inputHigh: 0, trig: Done.kr(loud), blocking: 1); stats = FluidBufStats.kr(~mfccbuf[voice], stats:~statsbuf[voice], numDerivs: 1, weights: ~weightbuf[voice], trig:Done.kr(weights), blocking: 1); - flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1); - FluidDataSetWr.kr(~dsW,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1); + flatten = FluidBufFlatten.kr(~statsbuf[voice], ~flatbuf[voice], trig:Done.kr(stats), blocking: 1); + FluidDataSetWr.kr(~dsW, label, nil, ~flatbuf[voice], Done.kr(flatten), blocking: 1); }); // and here we make a little processor for loudness if we want to poke at it @@ -47,10 +47,10 @@ var label, voice, loud, stats, flatten; label = data.key; voice = data.value[\voice]; - loud = FluidBufLoudness.kr(src,startFrame:start,numFrames:num,numChans:1,features:~mfccbuf[voice],trig:1,blocking: 1); + loud = FluidBufLoudness.kr(src, startFrame:start, numFrames:num, numChans:1, features:~mfccbuf[voice], trig:1, blocking: 1); stats = FluidBufStats.kr(~mfccbuf[voice], stats:~statsbuf[voice], numDerivs: 1, trig:Done.kr(loud), blocking: 1); - flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1); - FluidDataSetWr.kr(~dsL,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1); + flatten = FluidBufFlatten.kr(~statsbuf[voice], ~flatbuf[voice], trig:Done.kr(stats), blocking: 1); + FluidDataSetWr.kr(~dsL, label, nil, ~flatbuf[voice], Done.kr(flatten), blocking: 1); }); ) diff --git a/release-packaging/Examples/dataset/1-learning examples/11-compositing-datasets.scd b/release-packaging/Examples/dataset/1-learning examples/11-compositing-datasets.scd index 9b55fcf..5b3aee6 100644 --- a/release-packaging/Examples/dataset/1-learning examples/11-compositing-datasets.scd +++ b/release-packaging/Examples/dataset/1-learning examples/11-compositing-datasets.scd @@ -38,19 +38,19 @@ pitchweights = FluidBufThresh.kr(~pitchbuf[voice], numChans: 1, startChan: 1, destination: ~weightPitchbuf[voice], threshold: 0.7, trig:Done.kr(pitch), blocking: 1);//pull down low conf pitchstats = FluidBufStats.kr(~pitchbuf[voice], stats:~statsPitchbuf[voice], numDerivs: 1, weights: ~weightPitchbuf[voice], outliersCutoff: 1.5, trig:Done.kr(pitchweights), blocking: 1); pitchflat = FluidBufFlatten.kr(~statsPitchbuf[voice],~flatPitchbuf[voice],trig:Done.kr(pitchstats),blocking: 1); - writePitch = FluidDataSetWr.kr(~pitchDS,label, -1, ~flatPitchbuf[voice], Done.kr(pitchflat),blocking: 1); + writePitch = FluidDataSetWr.kr(~pitchDS,label, nil, ~flatPitchbuf[voice], Done.kr(pitchflat),blocking: 1); // the mfcc need loudness to weigh, so let's start with that loud = FluidBufLoudness.kr(src,startFrame:start, numFrames:num, numChans:1, features:~loudbuf[voice], trig:Done.kr(writePitch), blocking: 1);//here trig was 1 //we can now flatten and write Loudness in its own trigger tree statsLoud = FluidBufStats.kr(~loudbuf[voice], stats:~statsLoudbuf[voice], numDerivs: 1, trig:Done.kr(loud), blocking: 1); flattenLoud = FluidBufFlatten.kr(~statsLoudbuf[voice],~flatLoudbuf[voice],trig:Done.kr(statsLoud),blocking: 1); - writeLoud = FluidDataSetWr.kr(~loudDS,label, -1, ~flatLoudbuf[voice], Done.kr(flattenLoud),blocking: 1); + writeLoud = FluidDataSetWr.kr(~loudDS,label, nil, ~flatLoudbuf[voice], Done.kr(flattenLoud),blocking: 1); //we can resume from the loud computation trigger mfcc = FluidBufMFCC.kr(src,startFrame:start,numFrames:num,numChans:1,features:~mfccbuf[voice],trig:Done.kr(writeLoud),blocking: 1);//here trig was loud mfccweights = FluidBufScale.kr(~loudbuf[voice],numChans: 1,destination: ~weightMFCCbuf[voice],inputLow: -70,inputHigh: 0, trig: Done.kr(mfcc), blocking: 1); mfccstats = FluidBufStats.kr(~mfccbuf[voice], stats:~statsMFCCbuf[voice], startChan: 1, numDerivs: 1, weights: ~weightMFCCbuf[voice], trig:Done.kr(mfccweights), blocking: 1);//remove mfcc0 and weigh by loudness instead mfccflat = FluidBufFlatten.kr(~statsMFCCbuf[voice],~flatMFCCbuf[voice],trig:Done.kr(mfccstats),blocking: 1); - FluidDataSetWr.kr(~mfccDS,label, -1, ~flatMFCCbuf[voice], Done.kr(mfccflat),blocking: 1); + FluidDataSetWr.kr(~mfccDS,label, nil, ~flatMFCCbuf[voice], Done.kr(mfccflat),blocking: 1); }); ) diff --git a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd index 5167a5d..69d17d5 100644 --- a/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd +++ b/release-packaging/Examples/dataset/1-learning examples/12-windowed-clustered-segmentation.scd @@ -38,11 +38,11 @@ a = Slider(w, Rect(10, 20, 330, 20)) features = FluidBufMFCC.kr(src,startFrame:start,numFrames:num,numChans:1, numCoeffs: 20, features:~featuresbuf[voice],trig:1,blocking: 1); stats = FluidBufStats.kr(~featuresbuf[voice],stats:~statsbuf[voice],trig:Done.kr(features),blocking: 1); flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1); - writer = FluidDataSetWr.kr(~slicesMFCC,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1); + writer = FluidDataSetWr.kr(~slicesMFCC,label, nil, ~flatbuf[voice], Done.kr(flatten),blocking: 1); features = FluidBufSpectralShape.kr(src,startFrame:start,numFrames:num,numChans:1, features:~featuresbuf[voice],trig:Done.kr(writer),blocking: 1); stats = FluidBufStats.kr(~featuresbuf[voice],stats:~statsbuf[voice],trig:Done.kr(features),blocking: 1); flatten = FluidBufFlatten.kr(~statsbuf[voice],~flatbuf[voice],trig:Done.kr(stats),blocking: 1); - writer = FluidDataSetWr.kr(~slicesShapes,label, -1, ~flatbuf[voice], Done.kr(flatten),blocking: 1); + writer = FluidDataSetWr.kr(~slicesShapes,label, nil, ~flatbuf[voice], Done.kr(flatten),blocking: 1); }); ) diff --git a/release-packaging/Examples/dataset/1-learning examples/8c-mlp-regressor-as-dim-redux.scd b/release-packaging/Examples/dataset/1-learning examples/8c-mlp-regressor-as-dim-redux.scd index 6bf9101..6c59b6e 100644 --- a/release-packaging/Examples/dataset/1-learning examples/8c-mlp-regressor-as-dim-redux.scd +++ b/release-packaging/Examples/dataset/1-learning examples/8c-mlp-regressor-as-dim-redux.scd @@ -31,7 +31,7 @@ FluidBufMelBands.process(s,~audio, features: ~melfeatures,action: {\done.postln; 40.do{|i| bufWr = BufWr.kr(rd[i], buf, DC.kr(i)); }; - dsWr = FluidDataSetWr.kr(~raw, buf: buf, trig: Done.kr(stats)); + dsWr = FluidDataSetWr.kr(~raw, buf: buf, idNumber: count, trig: Done.kr(stats)); LocalOut.kr( Done.kr(dsWr)); FreeSelf.kr(count - 99); Poll.kr(trig,(100-count)); diff --git a/release-packaging/HelpSource/Classes/FluidMDS.schelp b/release-packaging/HelpSource/Classes/FluidMDS.schelp index c5444f2..b1f7722 100644 --- a/release-packaging/HelpSource/Classes/FluidMDS.schelp +++ b/release-packaging/HelpSource/Classes/FluidMDS.schelp @@ -89,14 +89,14 @@ FluidBufMFCC.process(s,~audio, features: ~mfcc_feature); var chunkLen = (~mfcc_feature.numFrames / 100).asInteger; var stats = FluidBufStats.kr( source: ~mfcc_feature, startFrame: count * chunkLen, - startChan:1, numFrames: chunkLen, stats: ~stats, trig: trig,blocking:1 + startChan:1, numFrames: chunkLen, stats: ~stats, trig: trig, blocking:1 ); var rd = BufRd.kr(12, ~stats, DC.kr(0), 0, 1); var bufWr, dsWr; 12.do{|i| bufWr = BufWr.kr(rd[i], buf, DC.kr(i)); }; - dsWr = FluidDataSetWr.kr(~raw, buf: buf, trig: Done.kr(stats),blocking:1); + dsWr = FluidDataSetWr.kr(~raw, buf: buf, idNumber: count, trig: Done.kr(stats),blocking:1); LocalOut.kr(Done.kr(dsWr)); FreeSelf.kr(count - 99); Poll.kr(trig,(100-count)); diff --git a/release-packaging/HelpSource/Classes/FluidNormalize.schelp b/release-packaging/HelpSource/Classes/FluidNormalize.schelp index d0b4043..5718cd6 100644 --- a/release-packaging/HelpSource/Classes/FluidNormalize.schelp +++ b/release-packaging/HelpSource/Classes/FluidNormalize.schelp @@ -97,7 +97,7 @@ FluidBufPitch.process(s,~audio, features: ~pitch_feature); var rd = BufRd.kr(2, ~stats, DC.kr(0), 0, 1);// pick only mean pitch and confidence var wr1 = BufWr.kr(rd[0], buf, DC.kr(0)); var wr2 = BufWr.kr(rd[1], buf, DC.kr(1)); - var dsWr = FluidDataSetWr.kr(~raw, buf: buf, trig: Done.kr(stats)); + var dsWr = FluidDataSetWr.kr(~raw, buf: buf, idNumber: count, trig: Done.kr(stats)); LocalOut.kr( Done.kr(dsWr)); Poll.kr(trig,count,\count); FreeSelf.kr(count - 9); diff --git a/release-packaging/HelpSource/Classes/FluidPCA.schelp b/release-packaging/HelpSource/Classes/FluidPCA.schelp index aaf6a00..d271202 100644 --- a/release-packaging/HelpSource/Classes/FluidPCA.schelp +++ b/release-packaging/HelpSource/Classes/FluidPCA.schelp @@ -59,7 +59,7 @@ Run when done. The function is passed code::destBuffer:: as argument. EXAMPLES:: code:: -s.boot; +s.reboot; //Preliminaries: we want some audio, a couple of FluidDataSets, some Buffers, a FluidStandardize and a FluidPCA ( ~audiofile = File.realpath(FluidBufPitch.class.filenameSymbol).dirname +/+ "../AudioFiles/Tremblay-ASWINE-ScratchySynth-M.wav"; @@ -99,7 +99,7 @@ FluidBufMFCC.process(s,~audio, features: ~mfcc_feature,action:{"Done MFCCs".post 12.do{|i| bufWr = BufWr.kr(rd[i], buf, DC.kr(i)); }; - dsWr = FluidDataSetWr.kr(~raw, buf: buf, trig: Done.kr(stats)); + dsWr = FluidDataSetWr.kr(~raw, buf: buf, idNumber: count, trig: Done.kr(stats)); LocalOut.kr( Done.kr(dsWr)); FreeSelf.kr(count - 99); Poll.kr(trig,(100 - count)); diff --git a/release-packaging/HelpSource/Classes/FluidProcessSlices.schelp b/release-packaging/HelpSource/Classes/FluidProcessSlices.schelp index 9e27f2e..5de64ec 100644 --- a/release-packaging/HelpSource/Classes/FluidProcessSlices.schelp +++ b/release-packaging/HelpSource/Classes/FluidProcessSlices.schelp @@ -52,7 +52,7 @@ code:: statsbuf = LocalBuf(7); pitch = FluidBufPitch.kr(src,start,num,numChans:1,features:~featurebuffers[voice]); stats = FluidBufStats.kr(~featurebuffers[voice],numChans:1, stats:statsbuf,trig:Done.kr(pitch)); - FluidDataSetWr.kr(label,statsbuf,~mydataset,Done.kr(stats)) + FluidDataSetWr.kr(~mydataset, label, nil, statsbuf,Done.kr(stats)) }; :: @@ -112,7 +112,7 @@ s.reboot; label = data.key; pitch = FluidBufPitch.kr(src,start,num,features:~pitchbufs[i]); stats = FluidBufStats.kr(~pitchbufs[i],stats:~statsbufs[i],trig:Done.kr(pitch)); - FluidDataSetWr.kr(~pitchdata,label,-1,buf:~statsbufs[i],trig:Done.kr(stats)) + FluidDataSetWr.kr(~pitchdata,label,nil,buf:~statsbufs[i],trig:Done.kr(stats)) }); ) diff --git a/release-packaging/HelpSource/Classes/FluidRobustScale.schelp b/release-packaging/HelpSource/Classes/FluidRobustScale.schelp index 85848a0..5237e55 100644 --- a/release-packaging/HelpSource/Classes/FluidRobustScale.schelp +++ b/release-packaging/HelpSource/Classes/FluidRobustScale.schelp @@ -96,7 +96,7 @@ FluidBufPitch.process(s,~audio, features: ~pitch_feature); var rd = BufRd.kr(2, ~stats, DC.kr(0), 0, 1);// pick only mean pitch and confidence var wr1 = BufWr.kr(rd[0], buf, DC.kr(0)); var wr2 = BufWr.kr(rd[1], buf, DC.kr(1)); - var dsWr = FluidDataSetWr.kr(~raw, buf: buf, trig: Done.kr(stats)); + var dsWr = FluidDataSetWr.kr(~raw, buf: buf, idNumber: count, trig: Done.kr(stats)); LocalOut.kr( Done.kr(dsWr)); Poll.kr(trig,count,\count); FreeSelf.kr(count - 9); diff --git a/release-packaging/HelpSource/Classes/FluidStandardize.schelp b/release-packaging/HelpSource/Classes/FluidStandardize.schelp index c4d3b2b..a10ceab 100644 --- a/release-packaging/HelpSource/Classes/FluidStandardize.schelp +++ b/release-packaging/HelpSource/Classes/FluidStandardize.schelp @@ -90,7 +90,7 @@ FluidBufPitch.process(s,~audio, features: ~pitch_feature,action:{"Analysed Pitch var rd = BufRd.kr(2, ~stats, DC.kr(0), 0, 1);// pick only mean pitch and confidence var wr1 = BufWr.kr(rd[0], buf, DC.kr(0)); var wr2 = BufWr.kr(rd[1], buf, DC.kr(1)); - var dsWr = FluidDataSetWr.kr(~raw, buf: buf, trig: Done.kr(stats)); + var dsWr = FluidDataSetWr.kr(~raw, buf: buf, idNumber: count, trig: Done.kr(stats)); LocalOut.kr( Done.kr(dsWr)); FreeSelf.kr(count - 9); Poll.kr(trig,count, \count); From 64ace358875ffe8b674a44a10be68e7bb38a391a Mon Sep 17 00:00:00 2001 From: Owen Green Date: Mon, 12 Apr 2021 12:39:56 +0100 Subject: [PATCH 24/32] Add padding param to BufLoudness --- release-packaging/Classes/FluidBufLoudness.sc | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/release-packaging/Classes/FluidBufLoudness.sc b/release-packaging/Classes/FluidBufLoudness.sc index 0d3644e..8b15d68 100644 --- a/release-packaging/Classes/FluidBufLoudness.sc +++ b/release-packaging/Classes/FluidBufLoudness.sc @@ -1,6 +1,6 @@ FluidBufLoudness : FluidBufProcessor{ - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, trig = 1, blocking = 0| - + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, trig = 1, blocking = 0| + var maxwindowSize = windowSize.nextPowerOfTwo; source = source.asUGenInput; @@ -8,12 +8,12 @@ FluidBufLoudness : FluidBufProcessor{ source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; - - ^FluidProxyUgen.kr(\FluidBufLoudnessTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, kWeighting, truePeak, windowSize, hopSize, maxwindowSize, trig, blocking); + + ^FluidProxyUgen.kr(\FluidBufLoudnessTrigger, -1, source, startFrame, numFrames, startChan, numChans, features,padding, kWeighting, truePeak, windowSize, hopSize, maxwindowSize, trig, blocking); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, freeWhenDone = true, action| - + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, freeWhenDone = true, action| + var maxwindowSize = windowSize.nextPowerOfTwo; source = source.asUGenInput; @@ -21,16 +21,16 @@ FluidBufLoudness : FluidBufProcessor{ source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; - + ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,0],freeWhenDone,action + [source, startFrame, numFrames, startChan, numChans, features, padding, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,0],freeWhenDone,action ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, freeWhenDone = true, action| - + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, freeWhenDone = true, action| + var maxwindowSize = windowSize.nextPowerOfTwo; source = source.asUGenInput; @@ -38,11 +38,11 @@ FluidBufLoudness : FluidBufProcessor{ source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; - + ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,1],freeWhenDone,action + [source, startFrame, numFrames, startChan, numChans, features,padding, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,1],freeWhenDone,action ); } } From f29c011e94dd8b11523c03fb837a4e857cf5db21 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Mon, 12 Apr 2021 15:00:03 +0100 Subject: [PATCH 25/32] Add padding param to BufLoudness --- release-packaging/Classes/FluidBufLoudness.sc | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/release-packaging/Classes/FluidBufLoudness.sc b/release-packaging/Classes/FluidBufLoudness.sc index 0d3644e..8b15d68 100644 --- a/release-packaging/Classes/FluidBufLoudness.sc +++ b/release-packaging/Classes/FluidBufLoudness.sc @@ -1,6 +1,6 @@ FluidBufLoudness : FluidBufProcessor{ - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, trig = 1, blocking = 0| - + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, trig = 1, blocking = 0| + var maxwindowSize = windowSize.nextPowerOfTwo; source = source.asUGenInput; @@ -8,12 +8,12 @@ FluidBufLoudness : FluidBufProcessor{ source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; - - ^FluidProxyUgen.kr(\FluidBufLoudnessTrigger, -1, source, startFrame, numFrames, startChan, numChans, features, kWeighting, truePeak, windowSize, hopSize, maxwindowSize, trig, blocking); + + ^FluidProxyUgen.kr(\FluidBufLoudnessTrigger, -1, source, startFrame, numFrames, startChan, numChans, features,padding, kWeighting, truePeak, windowSize, hopSize, maxwindowSize, trig, blocking); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, freeWhenDone = true, action| - + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, freeWhenDone = true, action| + var maxwindowSize = windowSize.nextPowerOfTwo; source = source.asUGenInput; @@ -21,16 +21,16 @@ FluidBufLoudness : FluidBufProcessor{ source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; - + ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,0],freeWhenDone,action + [source, startFrame, numFrames, startChan, numChans, features, padding, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,0],freeWhenDone,action ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, freeWhenDone = true, action| - + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, windowSize = 1024, hopSize = 512, padding = 1, freeWhenDone = true, action| + var maxwindowSize = windowSize.nextPowerOfTwo; source = source.asUGenInput; @@ -38,11 +38,11 @@ FluidBufLoudness : FluidBufProcessor{ source.isNil.if {"FluidBufPitch: Invalid source buffer".throw}; features.isNil.if {"FluidBufPitch: Invalid features buffer".throw}; - + ^this.new( server, nil, [features] ).processList( - [source, startFrame, numFrames, startChan, numChans, features, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,1],freeWhenDone,action + [source, startFrame, numFrames, startChan, numChans, features,padding, kWeighting, truePeak, windowSize, hopSize, maxwindowSize,1],freeWhenDone,action ); } } From 1c2995c02455530da92ea4392f710a8fc68ab97a Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Mon, 12 Apr 2021 15:24:06 +0100 Subject: [PATCH 26/32] added padding to loudness help --- release-packaging/HelpSource/Classes/FluidBufLoudness.schelp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release-packaging/HelpSource/Classes/FluidBufLoudness.schelp b/release-packaging/HelpSource/Classes/FluidBufLoudness.schelp index 74e0cae..86651fd 100644 --- a/release-packaging/HelpSource/Classes/FluidBufLoudness.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufLoudness.schelp @@ -51,6 +51,9 @@ ARGUMENT:: windowSize ARGUMENT:: hopSize How much the buffered window moves forward, in samples. By default 512 to be similar with all other FluCoMa objects, the EBU specifies other values as per the examples below. +ARGUMENT:: padding + Controls the zero-padding added to either end of the source buffer or segment. Possible values are 0 (no padding), 1 (default, half the window size), or 2 (window size - hop size). Padding ensures that all input samples are completely analysed: with no padding, the first analysis window starts at time 0, and the samples at either end will be tapered by the STFT windowing function. Mode 1 has the effect of centering the first sample in the analysis window and ensuring that the very start and end of the segment are accounted for in the analysis. Mode 2 can be useful when the overlap factor (window size / hop size) is greater than 2, to ensure that the input samples at either end of the segment are covered by the same number of analysis frames as the rest of the analysed material. + ARGUMENT:: freeWhenDone Free the server instance when processing complete. Default true From 54c1fc2e5b49da06c73c3fec5de362eaccf318e4 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 13 Apr 2021 09:40:25 +0100 Subject: [PATCH 27/32] fix example with new padding in loudness --- .../1-learning examples/10a-weighted-MFCCs-comparison.scd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/release-packaging/Examples/dataset/1-learning examples/10a-weighted-MFCCs-comparison.scd b/release-packaging/Examples/dataset/1-learning examples/10a-weighted-MFCCs-comparison.scd index ae629df..1dc091b 100644 --- a/release-packaging/Examples/dataset/1-learning examples/10a-weighted-MFCCs-comparison.scd +++ b/release-packaging/Examples/dataset/1-learning examples/10a-weighted-MFCCs-comparison.scd @@ -35,7 +35,7 @@ label = data.key; voice = data.value[\voice]; mfcc = FluidBufMFCC.kr(src, startFrame:start, numFrames:num, numChans:1, features:~mfccbuf[voice], padding: 2, trig:1, blocking: 1); - loud = FluidBufLoudness.kr(src, startFrame:start, numFrames:num, numChans:1, features:~loudbuf[voice], trig:Done.kr(mfcc), blocking: 1); + loud = FluidBufLoudness.kr(src, startFrame:start, numFrames:num, numChans:1, features:~loudbuf[voice], padding: 2, trig:Done.kr(mfcc), blocking: 1); weights = FluidBufScale.kr(~loudbuf[voice], numChans: 1, destination: ~weightbuf[voice], inputLow: -70, inputHigh: 0, trig: Done.kr(loud), blocking: 1); stats = FluidBufStats.kr(~mfccbuf[voice], stats:~statsbuf[voice], numDerivs: 1, weights: ~weightbuf[voice], trig:Done.kr(weights), blocking: 1); flatten = FluidBufFlatten.kr(~statsbuf[voice], ~flatbuf[voice], trig:Done.kr(stats), blocking: 1); @@ -47,7 +47,7 @@ var label, voice, loud, stats, flatten; label = data.key; voice = data.value[\voice]; - loud = FluidBufLoudness.kr(src, startFrame:start, numFrames:num, numChans:1, features:~mfccbuf[voice], trig:1, blocking: 1); + loud = FluidBufLoudness.kr(src, startFrame:start, numFrames:num, numChans:1, features:~mfccbuf[voice], trig:1, padding: 2, blocking: 1); stats = FluidBufStats.kr(~mfccbuf[voice], stats:~statsbuf[voice], numDerivs: 1, trig:Done.kr(loud), blocking: 1); flatten = FluidBufFlatten.kr(~statsbuf[voice], ~flatbuf[voice], trig:Done.kr(stats), blocking: 1); FluidDataSetWr.kr(~dsL, label, nil, ~flatbuf[voice], Done.kr(flatten), blocking: 1); @@ -150,10 +150,10 @@ FluidBufCompose.process(s,~loader.buffer,a,(b-a),numChans: 1, destination: ~targ ( { var loud, weights, mfcc, stats, flatten, stats2, written; - mfcc = FluidBufMFCC.kr(~targetsound,features:~mfccbuf[0],trig:1); + mfcc = FluidBufMFCC.kr(~targetsound,features:~mfccbuf[0],padding: 2, trig:1); stats = FluidBufStats.kr(~mfccbuf[0],stats:~statsbuf[0], numDerivs: 1,trig:Done.kr(mfcc)); flatten = FluidBufFlatten.kr(~statsbuf[0],~flatbuf[0],trig:Done.kr(stats)); - loud = FluidBufLoudness.kr(~targetsound,features:~loudbuf[0],trig:Done.kr(flatten),blocking: 1); + loud = FluidBufLoudness.kr(~targetsound,features:~loudbuf[0],padding: 2,trig:Done.kr(flatten),blocking: 1); weights = FluidBufScale.kr(~loudbuf[0],numChans: 1,destination: ~weightbuf[0],inputLow: -70,inputHigh: 0,trig: Done.kr(loud),blocking: 1); stats2 = FluidBufStats.kr(~mfccbuf[0],stats:~statsbuf[0], numDerivs: 1, weights: ~weightbuf[0], trig:Done.kr(weights),blocking: 1); written = FluidBufFlatten.kr(~statsbuf[0],~flatbuf[1],trig:Done.kr(stats2)); From f413364ff24e456658bfc111c8d763c2262d7d39 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 13 Apr 2021 09:40:54 +0100 Subject: [PATCH 28/32] KMeans - new methods - new extensive doc and examples --- .../HelpSource/Classes/FluidKMeans.schelp | 78 ++++++++++--------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidKMeans.schelp b/release-packaging/HelpSource/Classes/FluidKMeans.schelp index 8c49e9a..58d895c 100644 --- a/release-packaging/HelpSource/Classes/FluidKMeans.schelp +++ b/release-packaging/HelpSource/Classes/FluidKMeans.schelp @@ -25,7 +25,7 @@ INSTANCEMETHODS:: PRIVATE::k METHOD:: fit -Identify code::k:: clusters in a link::Classes/FluidDataSet:: +Identify code::numClusters:: clusters in a link::Classes/FluidDataSet::. It will optimise until no improvement is possible, or up to code::maxIter::, whichever comes first. Subsequent calls will continue training from the stopping point with the same conditions. ARGUMENT:: dataSet A link::Classes/FluidDataSet:: of data points. ARGUMENT:: action @@ -56,55 +56,51 @@ a link::Classes/Buffer:: containing a data point. ARGUMENT:: action A function to run when the server responds, taking the ID of the cluster as its argument. -METHOD:: predict -Report cluster assignments for previously unseen data. -ARGUMENT:: dataSet -A link::Classes/FluidDataSet:: of data points. -ARGUMENT:: labelSet -A link::Classes/FluidLabelSet:: to contain assignments. +METHOD:: transform +Given a trained object, return for each item of a provided DataSet its distance to each cluster as an array, often reffered to as the cluster-distance space. +ARGUMENT:: srcDataSet +A link::Classes/FluidDataSet:: of data points to transform. +ARGUMENT:: dstDataSet +A link::Classes/FluidDataSet:: to contain the new cluster-distance space. ARGUMENT:: action -A function to run when complete, taking an array of the counts for each category as its argument. +A function to run when complete. METHOD:: fitTransform -Run link::Classes/FluidKMeans#*fit:: and link::Classes/FluidKMeans#*predict:: in a single pass: i.e. train the model on the incoming link::Classes/FluidDataSet:: and then return the learned clustering to the passed link::Classes/FluidLabelSet:: +Run link::Classes/FluidKMeans#*fit:: and link::Classes/FluidKMeans#*transform:: in a single pass: i.e. train the model on the incoming link::Classes/FluidDataSet:: and then return its cluster-distance space in the destination link::Classes/FluidDataSet:: ARGUMENT:: srcDataSet a link::Classes/FluidDataSet:: containing the data to fit and predict. ARGUMENT:: dstDataSet -a link::Classes/FluidLabelSet:: to retrieve the predicted clusters. +A link::Classes/FluidDataSet:: to contain the new cluster-distance space. ARGUMENT:: action -A function to run when the server responds +A function to run when complete. METHOD:: transformPoint -Given a trained object, return the cluster ID for a data point in a link::Classes/Buffer:: +Given a trained object, return the distance of the provided point to each cluster. Both points are handled as link::Classes/Buffer:: ARGUMENT:: sourceBuffer -a link::Classes/Buffer:: containing a data point. +a link::Classes/Buffer:: containing a data point to query. ARGUMENT:: targetBuffer -a link::Classes/Buffer:: containing a data point. -ARGUMENT:: action -A function to run when the server responds, taking the ID of the cluster as its argument. - -METHOD:: transform -Report cluster assignments for previously unseen data. -ARGUMENT:: srcDataSet -A link::Classes/FluidDataSet:: of data points. -ARGUMENT:: dstDataSet -A link::Classes/FluidLabelSet:: to contain assignments. +a link::Classes/Buffer:: containing a the distance of the source point to each cluster. ARGUMENT:: action -A function to run when complete, taking an array of the counts for each category as its argument. +A function to run when complete. METHOD:: getMeans -Report cluster assignments for previously unseen data. +Given a trained object, retrieve the means (centroids) of each cluster as a link::Classes/FluidDataSet:: ARGUMENT:: dataSet -A link::Classes/FluidDataSet:: of data points. +A link::Classes/FluidDataSet:: of clusers with a mean per column. ARGUMENT:: action -A function to run when complete, taking an array of the counts for each category as its argument. +A function to run when complete. METHOD:: setMeans -Report cluster assignments for previously unseen data. +Overwrites the means (centroids) of each cluster, and declare the object trained. ARGUMENT:: dataSet -A link::Classes/FluidDataSet:: of data points. +A link::Classes/FluidDataSet:: of clusers with a mean per column. +ARGUMENT:: action +A function to run when complete. + +METHOD:: clear +Reset the object status to not fitted and untrained. ARGUMENT:: action -A function to run when complete, taking an array of the counts for each category as its argument. +A function to run when complete. EXAMPLES:: code:: @@ -192,30 +188,40 @@ subsection:: Accessing the means We can get and set the means for each cluster, their centroid. code:: +// with the dataset and kmeans generated and trained in the code above ~centroids = FluidDataSet(s); ~kmeans.getMeans(~centroids, {~centroids.print}); - - +// We can also set them to arbitrary values to seed the process ~centroids.load(Dictionary.newFrom([\cols, 2, \data, Dictionary.newFrom([\0, [0.5,0.5], \1, [-0.5,0.5], \2, [0.5,-0.5], \3, [-0.5,-0.5]])])); ~centroids.print ~kmeans.setMeans(~centroids, {~kmeans.predict(~dataSet,~clusters,{~clusters.dump{|x|var count = 0.dup(4); x["data"].keysValuesDo{|k,v|count[v[0].asInteger] = count[v[0].asInteger] + 1;};count.postln}})}); -~kmeans.clear -~kmeans.predict(~dataSet,~clusters) - +// We can further fit from the seeded means +~kmeans.fit(~dataSet) +// then retreive the improved means +~kmeans.getMeans(~centroids, {~centroids.print}); +//subtle in this case but still.. each quadrant is where we seeded it. :: subsection:: Cluster-distance Space -You can get the euclidian distance of a given point to each cluster. +We can get the euclidian distance of a given point to each cluster. This is often referred to as the cluster-distance space as it creates new dimensions for each given point, one distance per cluster. code:: +// with the dataset and kmeans generated and trained in the code above b = Buffer.sendCollection(s,[0.5,0.5]) c = Buffer(s) +// get the distance of our given point (b) to each cluster, thus giving us 4 dimensions in our cluster-distance space ~kmeans.transformPoint(b,c,{|x|x.query;x.getn(0,x.numFrames,{|y|y.postln})}) +// we can also transform a full dataset +~srcDS = FluidDataSet(s) +~cdspace = FluidDataSet(s) +// make a new dataset with 4 points +~srcDS.load(Dictionary.newFrom([\cols, 2, \data, Dictionary.newFrom([\pp, [0.5,0.5], \np, [-0.5,0.5], \pn, [0.5,-0.5], \nn, [-0.5,-0.5]])])); +~kmeans.transform(~srcDS, ~cdspace, {~cdspace.print}) :: subsection:: Queries in a Synth From cc13acc9523de0df20ef2580fb2548ee326e5573 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 13 Apr 2021 09:58:36 +0100 Subject: [PATCH 29/32] and now, with less typos --- .../HelpSource/Classes/FluidKMeans.schelp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidKMeans.schelp b/release-packaging/HelpSource/Classes/FluidKMeans.schelp index 58d895c..1dcf71f 100644 --- a/release-packaging/HelpSource/Classes/FluidKMeans.schelp +++ b/release-packaging/HelpSource/Classes/FluidKMeans.schelp @@ -32,11 +32,11 @@ ARGUMENT:: action A function to run when fitting is complete, taking as its argument an array with the number of data points for each cluster. METHOD:: predict -Given a trained object, return the cluster ID for each data point in a DataSet to a label set. +Given a trained object, return the cluster ID for each data point in a link::Classes/FluidDataSet:: to a link::Classes/FluidLabelSet::. ARGUMENT:: dataSet -a link::Classes/FluidDataSet:: containing the data to predict. +A link::Classes/FluidDataSet:: containing the data to predict. ARGUMENT:: labelSet -a link::Classes/FluidLabelSet:: to retrieve the predicted clusters. +A link::Classes/FluidLabelSet:: to retrieve the predicted clusters. ARGUMENT:: action A function to run when the server responds. @@ -52,12 +52,12 @@ A function to run when the server responds METHOD:: predictPoint Given a trained object, return the cluster ID for a data point in a link::Classes/Buffer:: ARGUMENT:: buffer -a link::Classes/Buffer:: containing a data point. +A link::Classes/Buffer:: containing a data point. ARGUMENT:: action A function to run when the server responds, taking the ID of the cluster as its argument. METHOD:: transform -Given a trained object, return for each item of a provided DataSet its distance to each cluster as an array, often reffered to as the cluster-distance space. +Given a trained object, return for each item of a provided link::Classes/FluidDataSet:: its distance to each cluster as an array, often reffered to as the cluster-distance space. ARGUMENT:: srcDataSet A link::Classes/FluidDataSet:: of data points to transform. ARGUMENT:: dstDataSet @@ -68,7 +68,7 @@ A function to run when complete. METHOD:: fitTransform Run link::Classes/FluidKMeans#*fit:: and link::Classes/FluidKMeans#*transform:: in a single pass: i.e. train the model on the incoming link::Classes/FluidDataSet:: and then return its cluster-distance space in the destination link::Classes/FluidDataSet:: ARGUMENT:: srcDataSet -a link::Classes/FluidDataSet:: containing the data to fit and predict. +A link::Classes/FluidDataSet:: containing the data to fit and transform. ARGUMENT:: dstDataSet A link::Classes/FluidDataSet:: to contain the new cluster-distance space. ARGUMENT:: action @@ -77,9 +77,9 @@ A function to run when complete. METHOD:: transformPoint Given a trained object, return the distance of the provided point to each cluster. Both points are handled as link::Classes/Buffer:: ARGUMENT:: sourceBuffer -a link::Classes/Buffer:: containing a data point to query. +A link::Classes/Buffer:: containing a data point to query. ARGUMENT:: targetBuffer -a link::Classes/Buffer:: containing a the distance of the source point to each cluster. +A link::Classes/Buffer:: containing a the distance of the source point to each cluster. ARGUMENT:: action A function to run when complete. From 3fdeaeb833e219fc750ab583baf065e3a6c0b239 Mon Sep 17 00:00:00 2001 From: Owen Green Date: Tue, 13 Apr 2021 23:56:01 +0100 Subject: [PATCH 30/32] Fix latency u_cmd by defining after the server knows the Unit exists --- include/wrapper/Realtime.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/wrapper/Realtime.hpp b/include/wrapper/Realtime.hpp index e6e183a..64bff83 100644 --- a/include/wrapper/Realtime.hpp +++ b/include/wrapper/Realtime.hpp @@ -34,8 +34,9 @@ public: static void setup(InterfaceTable* ft, const char* name) { - ft->fDefineUnitCmd(name, "latency", doLatency); + registerUnit(ft,name); + ft->fDefineUnitCmd(name, "latency", doLatency); } static void doLatency(Unit* unit, sc_msg_iter*) @@ -47,7 +48,7 @@ public: std::stringstream ss; ss << '/' << Wrapper::getName() << "_latency"; - std::cout << ss.str() << std::endl; + // std::cout << ss.str() << ": " << l[0] << std::endl; ft->fSendNodeReply(&unit->mParent->mNode, -1, ss.str().c_str(), 1, l); } From 3ef8209d2815321e4ab6d1ae851255c01a251d94 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 14 Apr 2021 10:44:05 +0100 Subject: [PATCH 31/32] explanation of FFT impact in (buf)audiotransport with fun sounds --- .../HelpSource/Classes/FluidAudioTransport.schelp | 9 +++++++++ .../HelpSource/Classes/FluidBufAudioTransport.schelp | 2 ++ 2 files changed, 11 insertions(+) diff --git a/release-packaging/HelpSource/Classes/FluidAudioTransport.schelp b/release-packaging/HelpSource/Classes/FluidAudioTransport.schelp index 8f629ea..d56c1c5 100644 --- a/release-packaging/HelpSource/Classes/FluidAudioTransport.schelp +++ b/release-packaging/HelpSource/Classes/FluidAudioTransport.schelp @@ -47,6 +47,15 @@ code:: //didactic - the mouse X axis interpolates between the two sinewaves {FluidAudioTransport.ar(SinOsc.ar(220,mul: 0.1),SinOsc.ar(440,mul: 0.02),MouseX.kr())}.play; +//notice how the interpolation quantizes to the FFT bins. Like most spectral processes, it benefits from oversampling the fft... at the cost of CPU power, obviously. +{FluidAudioTransport.ar(SinOsc.ar(220,mul: 0.1),SinOsc.ar(440,mul: 0.02),MouseX.kr(),fftSize: 8192)}.play; + +// when the signal is steady, larger hopSize can be accommodated to save back on the CPU +{FluidAudioTransport.ar(SinOsc.ar(220,mul: 0.1),SinOsc.ar(440,mul: 0.02),MouseX.kr(),windowSize: 8192)}.play; // here we get a default hop of half the window so 8 times less than above. + +//if you CPU can cope, try this setting, almost smooth, but attacks would smear (the Y axis mixes some in to hear the effect) +{var attacks = Impulse.ar(1,mul: MouseY.kr(-40,10).dbamp); FluidAudioTransport.ar(SinOsc.ar(220,mul: 0.1,add: attacks),SinOsc.ar(440,mul: 0.02,add: attacks),MouseX.kr(),windowSize: 16000)}.play; + //richer with complex spectra //load 2 files ( diff --git a/release-packaging/HelpSource/Classes/FluidBufAudioTransport.schelp b/release-packaging/HelpSource/Classes/FluidBufAudioTransport.schelp index a202579..a960987 100644 --- a/release-packaging/HelpSource/Classes/FluidBufAudioTransport.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufAudioTransport.schelp @@ -94,6 +94,8 @@ b.play c.play d.play +// note that the process is quantized by the spectral bins. For an example of the pros and cons of these settings on this given process, please see the real-time FluidAudioTransport helpfile. + // more interesting sources: two cardboard bowing gestures ( b = Buffer.read(s,File.realpath(FluidBufAudioTransport.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Green-Box641.wav"); From 04ee2dbbb7215e8856a3dc1e62a22fa11af65831 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Wed, 14 Apr 2021 10:44:56 +0100 Subject: [PATCH 32/32] bufstats: better example of usage of derivative. --- .../HelpSource/Classes/FluidBufStats.schelp | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/release-packaging/HelpSource/Classes/FluidBufStats.schelp b/release-packaging/HelpSource/Classes/FluidBufStats.schelp index 0a6a0e3..39aae16 100644 --- a/release-packaging/HelpSource/Classes/FluidBufStats.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufStats.schelp @@ -129,43 +129,66 @@ STRONG::A musical example:: CODE:: // create some buffers ( -b = Buffer.read(s,File.realpath(FluidBufStats.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-ASWINE-ScratchySynth-M.wav"); +// a simple random sliding bell synth +b = { + var trig = Impulse.ar(1.5); + SinOsc.ar( + Lag.ar(TRand.ar(trig: trig), + TRand.ar(0.5, trig: trig)).exprange(333,666), + mul: Decay.ar( + trig * TRand.ar(0.1,10,trig), + TRand.ar(0.5,1.1,trig) + ) + ).atan * 0.1; +}.asBuffer(20); c = Buffer.new(s); d = Buffer.new(s); +i = Buffer.new(s); ) +//play the source +b.play; + //split in various chunks, collecting the indices in an array -FluidBufOnsetSlice.process(s,b, minSliceLength: 10, metric: 9, threshold: 0.4, filterSize: 7, indices: c, action:{c.loadToFloatArray(action: {|array| e = array.add(b.numFrames).addFirst(0);e.postln;})}); +FluidBufOnsetSlice.process(s,b, threshold: 0.01, indices: c, action:{c.loadToFloatArray(action: {|array| e = array.add(b.numFrames);e.size.postln;e.postln;})}); //describe the whole input too, here using pitch, and collecting the values in an array, dismissing the (interleaved) confidence. -FluidBufPitch.process(s,b,features:c, action:{c.loadToFloatArray(action: {|array| f = array.unlace(2)[0]; f.postln;})}); +FluidBufPitch.process(s,b,features:d, windowSize: 4096, hopSize: 512, padding:2, action:{d.loadToFloatArray(action: {|array| f = array.unlace(2)[0]; f.postln;})}); // iterate through each slice, taking the median of the first derivative of the pitch of each ( g= Array.new; Routine({ + var nb = e.size; e.doAdjacentPairs({ arg start,end; - FluidBufStats.processBlocking(s,c,(start/512).asInteger,((end-start)/512).max(2).asInteger,0,1,d,1, - action: {d.loadToFloatArray(action: { - arg array; - g = g.add(array[12]); - "% % %\n".postf((start/512).asInteger,((end-start)/512 ).max(2).asInteger, array[12]);}) - } - ).wait; -}); - "Done".postln; + FluidBufStats.processBlocking(s,d,(start/512).asInteger,((end-start)/512).asInteger + 3,0,1,i,1, action: { + i.loadToFloatArray( action: { + arg array; + g = g.add(array[12]); + "% % %\n".postf((start/512).asInteger,((end-start)/512).asInteger + 3, array[12]);//adding some of the overlap but not more to not capture too much of the next attack + nb = nb - 1; + if (nb == 1, {"Done".postln;});//check if we've done all the pairs + }) + }).wait; + }); }).play; ) -//obtain the order of indices that would sort the stats -h = g.order; +//play in loop the slice in order of pitch direction (the median of the slice's pitch variation) - mouse on the left should be descending, in the middle should be more stable, and it should be ascending on the right. -//play in loop the slice in order of pitch direction (the median of the slice's pitch variation) ( -var which = h[5]; -{BufRd.ar(1, b, Phasor.ar(0,1,e[which],e[which+1],e[which]))}.play; +Buffer.sendCollection(s,g.order,action: {|x| { + var which = BufRd.kr(1, x, MouseX.kr(0, BufFrames.kr(x) - 1), 0, 1); + BufRd.ar(1, b, + Phasor.ar(0,1, + BufRd.kr(1,c,which,0,1), + BufRd.kr(1,c,which + 1,0,1), + BufRd.kr(1,c,which,0,1))); + }.play; + };) ) + ::