You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
4.6 KiB
Markdown

// TB2 SC Playground V0
/*
Current stinkers:
1) Producing flat datapoints for FluidDataSet (i.e. flattening and cherry picking a multichannel buffer) takes bloody ages due to all the server syncing. I can't work out how to do it reliably outwith a Routine (which would certainly be quicker, to my mind)
2) Functions from the classes don't yet directly return things, and you have to access their return data through actions. This is partly because I don't know what the correct thing to do w/r/t blocking is, so I'm hoping GR will do it properly
*/
//STEP 0: start server
s.reboot;
if(s.hasBooted.not){"Warning: server not running".postln};
//STEP 1: Get some files
Buffer.freeAll;
(
FileDialog.new(fileMode:2,okFunc:{|x| ~path = x[0];
~audioBuffers = SoundFile.collectIntoBuffers(~path+/+'*',s);
~lookup = Dictionary(n:~audioBuffers.size);
~audioBuffers.do{|b| ~lookup.add(b.path->b)};
});
)
//STEP 2: Make a FluidDataSet
~dataset = FluidDataSet.new(s,"mfccs");
//STEP 3A: EITHER populate the dataset like so (and cry about how long the data point assembly takes)
(
Routine{
var tmpMFCCs = Buffer.new(s);
var tmpStats = Buffer.new(s);
var tmpFlat = Buffer.alloc(s,12 * 4 * 2, 1);//12 dims * 4 stats * 2 derivatives
s.sync;
~audioBuffers.do{|b|
("Analyzing" + b.path).postln;
FluidBufMFCC.process(s,b,features: tmpMFCCs);
FluidBufStats.process(s,source:tmpMFCCs, stats: tmpStats,numDerivs:1);
"stats".postln;
12.do{|i|
//This takes ages becayse of server syncing :-(
FluidBufCompose.process(s,tmpStats,0,2, i+1,1, destination: tmpFlat, destStartFrame: (i*8));
FluidBufCompose.process(s,tmpStats,4,1, i+1,1, destination: tmpFlat, destStartFrame: (i*8) + 2);
FluidBufCompose.process(s,tmpStats,6,3, i+1,1, destination:tmpFlat, destStartFrame: (i*8) + 3);
FluidBufCompose.process(s,tmpStats,11,1, i+1,1, destination: tmpFlat, destStartFrame: (i*8) + 6);
FluidBufCompose.process(s,tmpStats,13,1, i+1,1, destination:tmpFlat, destStartFrame: (i*8) + 7);
};
~dataset.addPoint(b.path,tmpFlat);
};
s.sync;
"Done".postln;
tmpFlat.free;
tmpStats.free;
tmpMFCCs.free;
}.play
)
//STEP 3B: OR populate the dataset with the flattening happening in langage side (much faster for now)
(
Routine{
var tmpMFCCs = Buffer.new(s);
var tmpStats = Buffer.new(s);
var langStats;
var langFlat;
var tmpFlat = Buffer.alloc(s,12 * 4 * 2, 1); //12 dims * 4 stats * 2 derivatives
s.sync;
~audioBuffers.do{|b|
("Analyzing" + b.path).postln;
FluidBufMFCC.process(s,b,features: tmpMFCCs);
FluidBufStats.process(s,source:tmpMFCCs, stats: tmpStats,numDerivs:1);
tmpStats.getn(0,182,{|y| langStats = y;});
s.sync;
"stats".postln;
langFlat = Array.new();
//taking the mean, std, min and max, and the mean, std, min and max of the first derivative, of each MFCCs except coeff 0 to dismiss amplitude)
[0,1,4,6,7,8,11,13].do({|i| var j,k; j =((i*13)+1); k = j + 11;langFlat = langFlat ++ langStats[j..k]});
tmpFlat.setn(0,langFlat);
s.sync;
~dataset.addPoint(b.path,tmpFlat);
};
s.sync;
"Done".postln;
tmpStats.free;
tmpMFCCs.free;
tmpFlat.free;
}.play
)
//check
~dataset.size({|x| x.postln})
//save
(
FileDialog.new(fileMode: 0, acceptMode: 1, okFunc:{|x| var file = x[0];
//if the file exists and is a json, delete it
if ((file.splitext[1] == "json") && (File.existsCaseSensitive(file)), {File.delete(file);"File Overwritten".postln;});
//if not json, make it so
if (file.splitext[1] != "json", {file = file ++ ".json";});
// then write
~dataset.write(file);
});
)
//STEP 3C: OR load in one you rolled earlier
FileDialog.new(fileMode: 0, acceptMode: 0, okFunc:{|x| ~dataset.read(x[0])});
//peek
c = Buffer.new(s)
~dataset.getPoint(~audioBuffers[3].path,c, { c.getn(0,96,{|x| x.postln})})
/*************************************/
//FluidKDTree
~kdtree = FluidKDTree.new(s)
~kdtree.fit(~dataset,action:{"fit".postln})
//match
~kdtree.kNearest(c,5,{|x| ~matches = x;})
~kdtree.kNearestDist(c,5,{|x| x.postln})
~lookup[~matches[4]].postln
/*************************************/
//FluidKMeans
~kMeans= FluidKMeans.new(s)
~kMeans.fit(~dataset,k:5,action:{"fit".postln})
// predicts in which cluster a point would be
~kMeans.predictPoint(c,{|x|x.postln})
// predicts which cluster each points of a dataset would be in, as a label
~labels = FluidLabelSet.new(s,"clusters")
~kMeans.predict(~dataset,~labels, {|x| x.postln})
~labels.getLabel(~audioBuffers[2].path,action:{|c| c.postln})
//query each item
(
Routine{
~labels.size({|x|x.do {|i|
~audioBuffers[i].path.postln;
~labels.getLabel(~audioBuffers[i].path,action:{|c| c.postln});
s.sync;
}
});
}.play
)
//labelset can be written as json
~labels.write(~path+/+"labels.json")