Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 30 additions & 17 deletions doc/Standardize.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,13 @@
:sc-related: Classes/FluidDataSet, Classes/FluidStandardize
:see-also:
:description:
Standardize a :fluid-obj:`DataSet`, i.e. rescale using its mean(s) and standard deviation(s) in each dimension.

See http://www.faqs.org/faqs/ai-faq/neural-nets/part2/section-16.html



:control invert:

The direction in which the standardization will occur for transform and transformpoint. The default 0 is taking in the range of the input used to fit and transforms it towards the standardized range. A value of 1 will expect an input of the standardized range to transform back to the original range.

Standardize a :fluid-obj:`DataSet`. Rescale using its mean(s) and standard deviation(s) in each dimension, such that each dimension has a mean of 0 and a standard deviation of 1.

:discussion:

:message fit:

:arg dataSet: The :fluid-obj:`DataSet` to standardize
:arg dataSet: The :fluid-obj:`DataSet` to learn the statistics of (mean and standard deviation)

:arg action: A function to run when processing is complete

Expand All @@ -27,28 +20,48 @@

:arg sourceDataSet: The :fluid-obj:`DataSet` to standardize

:arg destDataSet: The :fluid-obj:`DataSet` to populate with standardized data
:arg destDataSet: The :fluid-obj:`DataSet` to write the standardized data into

:arg action: A function to run when processing is complete

Standardize a :fluid-obj:`DataSet`, using the learned statistics from a previous call to :fluid-obj:`Standardize#fit`

:message fitTransform:

:arg sourceDataSet: The :fluid-obj:`DataSet` to standardize
:arg sourceDataSet: The :fluid-obj:`DataSet` to first ``fit`` to and then standardize

:arg destDataSet: The :fluid-obj:`DataSet` to populate with standardized data

:arg action: A function to run when processing is complete

Standardize a :fluid-obj:`DataSet` into another :fluid-obj:`DataSet`
``fit`` the model to the ``sourceDataSet`` and then standardize the ``sourceDataSet`` and write into ``destDataSet``

:message inverseTransform:

:arg sourceDataSet: The :fluid-obj:`DataSet` to of data to transform from the standardized scale to the original scale.

:arg destDataSet: The :fluid-obj:`DataSet` to write the transformed data to.

:arg action: A function to run when processing is complete

Un-standardize a :fluid-obj:`DataSet`, using the learned statistics from a previous call to :fluid-obj:`Standardize#fit`.

:message transformPoint:

:arg sourceBuffer: A |buffer| with the new data point
:arg sourceBuffer: A |buffer| with source data to standardize

:arg destBuffer: A |buffer| to contain the standardize value
:arg destBuffer: A |buffer| to write the standardized data into

:arg action: A function to run when processing is complete

Standardize a new data point, using the learned statistics from a previous call to :fluid-obj:`Standardize#fit`
Standardize a data point, using the learned statistics from a previous call to :fluid-obj:`Standardize#fit`

:message inverseTransformPoint:

:arg sourceBuffer: A |buffer| with the data in the stadardized range

:arg destBuffer: A |buffer| to write the output of the transformation to

:arg action: A function to run when processing is complete

Un-standardize a data point, using the learned statistics from a previous call to :fluid-obj:`Standardize#fit`
110 changes: 30 additions & 80 deletions example-code/sc/Standardize.scd
Original file line number Diff line number Diff line change
@@ -1,94 +1,44 @@
code::
s.boot;
//Preliminaries: we want some audio, a couple of FluidDataSets, some Buffers and a FluidStandardize
(
~audiofile = FluidFilesPath("Tremblay-ASWINE-ScratchySynth-M.wav");
~raw = FluidDataSet(s);
~stand = FluidDataSet(s);
~audio = Buffer.read(s,~audiofile);
~pitch_feature = Buffer.new(s);
~stats = Buffer.alloc(s, 7, 2);
~standardizer = FluidStandardize(s);
)


// Load audio and run a pitch analysis, which gives us pitch and pitch confidence (so a 2D datum)
(
~audio = Buffer.read(s,~audiofile);
FluidBufPitch.process(s,~audio, features: ~pitch_feature,action:{"Analysed Pitch".postln});
)
~src = Buffer.read(s,FluidFilesPath("Tremblay-UW-ComplexDescent-M.wav"));

// Divide the time series in to 10, and take the mean of each s"egment and add this as a point to
// the 'raw' FluidDataSet
// standardize a spectral analysis
(
{
var trig = LocalIn.kr(1, 1);
var buf = LocalBuf(2, 1);
var count = PulseCount.kr(trig) - 1;
var chunkLen = (~pitch_feature.numFrames / 10).asInteger;
var stats = FluidBufStats.kr(
source: ~pitch_feature, startFrame: count * chunkLen,
numFrames: chunkLen, stats: ~stats,
trig: trig * (count < 10), blocking: 1
);
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, idNumber: count, trig: Done.kr(stats));
LocalOut.kr( Done.kr(dsWr));
FreeSelf.kr(count - 9);
Poll.kr(trig,count, \count);
}.play;
)

// Standardize and load to language-side array
(
~rawarray = Array.new(10);
~stdarray= Array.new(10);
~standardizer.fitTransform(~raw,~stand, {
~raw.dump{|x| 10.do{|i|
~rawarray.add(x["data"][i.asString])
}};
~stand.dump{|x| 10.do{|i|
~stdarray.add(x["data"][i.asString])
}};
~select = [\centroid,\skewness];
~features = Buffer(s);
FluidBufSpectralShape.processBlocking(s,~src,features:~features,select:~select);
~ds = FluidDataSet(s).fromBuffer(~features);
"Firs the Raw Data, then the Standardized Data:".postln;
~ds.print;
~stand = FluidStandardize(s).fitTransform(~ds,~ds);
~ds.print;
~norm = FluidNormalize(s).fitTransform(~ds,~ds); // normalize just for plotting
~ds.dump({
arg dict;
defer{FluidPlotter(dict:dict)}
});
)

(
(~rawarray ++ 0).flop.plot("Unstandardized",Rect(0,0,400,400),minval:0,maxval:[5000,1]).plotMode=\bars;
(~stdarray ++ 0).flop.plot("Standardized",Rect(410,0,400,400), minval:-2,maxval:2).plotMode=\bars;
)

// single point transform on arbitrary value
~inbuf = Buffer.loadCollection(s,0.5.dup);
~outbuf = Buffer.new(s);
~standardizer.transformPoint(~inbuf,~outbuf,{|x|x.postln;x.getn(0,2,{|y|y.postln;};)});

::

subsection::Server Side Querying
strong::Server-side Querying::
code::

(
// read frames out of buffer and pass to standardize
{
var audio = BufRd.ar(1,~audio,LFSaw.ar(BufDur.ir(~audio).reciprocal).range(0, BufFrames.ir(~audio)));
var counter = Stepper.ar(Impulse.ar(ControlRate.ir),max:99);
var trig = A2K.kr(HPZ1.ar(counter) < 0);
//average 10 frames: one could use the MovingAverage extension here
var avg;
var inputPoint= LocalBuf(2);
var outputPoint = LocalBuf(2);
var avgBuf = LocalBuf(100,2);
//average of pitch features
BufWr.kr(FluidPitch.kr(audio),avgBuf,phase:counter);
avg = Mix.new(BufRd.kr(2, avgBuf, phase:100.collect{|x|x})) * 0.01;
//assemble data point
BufWr.kr(avg[0],inputPoint,0);
BufWr.kr(avg[1],inputPoint,1);
Poll.kr(trig,BufRd.kr(1,inputPoint,[0,1]),["pitch (raw)", "confidence (raw)"]);
~standardizer.kr(trig,inputPoint,outputPoint);
Poll.kr(trig,BufRd.kr(1,outputPoint,[0,1]),["pitch (standardized)", "confidence (standardized)"]);
var src = PlayBuf.ar(1,~src,BufRateScale.ir(~src),loop:1);
var inputPoint = LocalBuf(2);
var outputPoint = LocalBuf(2);
var analysis = FluidSpectralShape.kr(src,~select);
var standardized, sig;

analysis.poll(label:"Raw Analysis");
FluidKrToBuf.kr(analysis,inputPoint);
~stand.kr(Impulse.kr(100),inputPoint,outputPoint);
standardized = FluidBufToKr.kr(outputPoint);
standardized.poll(label:"Standardized Analysis");

sig = PitchShift.ar(src,0.2,(standardized * [-5,1]).midiratio,standardized.reverse.abs.midiratio);
sig;
}.play;
)
::