Hi, I noticed for what I want to do I can’t use bufstats~. It’s way to slow if you have many slices. I guess it’s all this repeated buffer handling. I’m trying to calculate the stats myself currently with a js. Later I want to normalize and do distance calculations. I came up with some questions:
- What are the derivative values? How to calculate and what do they describe?
- How do I absolutely normalize skewness and kurtosis? Are they in the same unit as the feature? What is the minimum / maximum of it?(for any input) And is it linear?
Here is the script for the stats per slice output. Only kurtosis results seem to slightly differ from bufstats~ results. (Couldn’t find the actual formula on flucoma github code) Hence my question 1, I was wondering if I should add derivative calculation when I understand what it is…
outlets=2;
function get(sourcebuf, slicebuf, featbuf, featbufchan, hopsize)
{
var source_buffer = new Buffer(sourcebuf);
var slice_buffer = new Buffer(slicebuf);
var feat_buffer = new Buffer(featbuf);
var numOfSlices = slice_buffer.framecount();
var onsetArr = slice_buffer.peek(0, 0, numOfSlices);
//post ("\nnum of slices: "+ numOfSlices);
//post("\nfeat frames: "+ feat_buffer.framecount());
//for every onset
for (i = 0; i < numOfSlices; i++)
{
var onsetTimeInSamples = onsetArr[i];
var lengthInSamples;
if (i == numOfSlices-1)//last one
{
lengthInSamples = source_buffer.framecount()-onsetTimeInSamples;
}
else
{
lengthInSamples = onsetArr[i+1]-onsetTimeInSamples;
}
var start = ~~(onsetTimeInSamples / hopsize);
var length = ~~(lengthInSamples / hopsize);
//post ("\nslice: "+ i +" feat start: "+start+" len: "+length );
var featArr = feat_buffer.peek(featbufchan, start, length);
// skewness
// kurtosis
delta = 0,
delta_n = 0,
delta_n2 = 0,
term1 = 0,
N = 0,
mean2 = 0,
M2 = 0,
M3 = 0,
M4 = 0,
sk_g = 0,
ku_g = 0;
var mean = 0;
var minimum = (Math.pow(2, 53) - 1);
var maximum = -(Math.pow(2, 53) - 1);
var stddev = 0;
var skewness = 0;
var kurtosis = 0;
var median = 0;
for (var j = 0 ; j < length; j++)
{
var value = featArr[j];
if (value > maximum)
maximum = value;
if (value < minimum)
minimum = value;
mean+=value;
N += 1;
delta = value - mean2;
delta_n = delta / N;
delta_n2 = delta_n * delta_n;
term1 = delta * delta_n * (N-1);
M4 += term1*delta_n2*(N*N - 3*N + 3) + 6*delta_n2*M2 - 4*delta_n*M3;
M3 += term1*delta_n*(N-2) - 3*delta_n*M2;
M2 += term1;
mean2 += delta_n;
}
mean /= length;
sk_g = Math.sqrt( N )*M3 / Math.pow( M2, 3/2 );
ku_g = N*M4 / ( M2*M2 ) - 3;
skewness = Math.sqrt( N*(N-1))*sk_g / (N-2);
kurtosis = (N-1) / ( (N-2)*(N-3) ) * ( (N+1)*ku_g + 6 );
//post (" mean: "+ mean +" maximum: "+maximum+" minimum: "+minimum );
for (var j = 0 ; j < length; j++)
{
var value = featArr[j];
stddev += Math.pow((value - mean),2);
}
stddev = Math.sqrt(stddev/length);
featArr.sort( function(a, b){return a - b} );
// Get the middle index:
id = Math.floor( length / 2 );
if ( length % 2 )
{
// The number of elements is not evenly divisible by two, hence we have a middle index:
median = featArr[ id ];
}
else
// Even number of elements, so must take the mean of the two middle values:
median = ( featArr[ id-1 ] + featArr[ id ] ) / 2.0;
outlet(1, i, mean, stddev, skewness, kurtosis, minimum, median, maximum);
}// end loop over onsets
outlet(0, "bang");
}