I guess one simpler question would be:
When plotting with MFCC and umap, I’m visualizing a lot of somewhat abstract analysis information that I don’t necessarily understand - other than what I’m able to glean intuitively from working with a plotter. Arguably, if I were to dump the results into single buffers, I could use the X/Y coordinates as file names - but I wonder if there would be a way to title the files with concrete information about the MFCC make-up in each. I’ve pasted the code below, but commented the area that I imagine this taking place in..
~folder = FluidFilesPath();
~loader = FluidLoadFolder(~folder).play(s,{"done loading folder".postln;});
// sum to mono
(
if(~loader.buffer.numChannels > 1){
~src = Buffer(s);
~loader.buffer.numChannels.do{
arg chan_i;
FluidBufCompose.processBlocking(s,
~loader.buffer,
startChan:chan_i,
numChans:1,
gain:~loader.buffer.numChannels.reciprocal,
destination:~src,
destGain:1,
action:{"copied channel: %".format(chan_i).postln}
);
};
}{
"loader buffer is already mono".postln;
~src = ~loader.buffer;
};
)
// slice the buffer in non real-time
(
~indices = Buffer(s);
FluidBufOnsetSlice.processBlocking(s,~src,metric:9,threshold:0.05,indices:~indices,action:{
"found % slice points".format(~indices.numFrames).postln;
"average duration per slice: %".format(~src.duration / (~indices.numFrames+1)).postln;
});
)
// analysis
(
~analyses = FluidDataSet(s);
~indices.loadToFloatArray(action:{
arg fa;
var mfccs = Buffer(s);
var stats = Buffer(s);
var flat = Buffer(s);
fa.doAdjacentPairs{
arg start, end, i;
var num = end - start;
FluidBufMFCC.processBlocking(s,~src,start,num,features:mfccs,numCoeffs:13,startCoeff:1);
FluidBufStats.processBlocking(s,mfccs,stats:stats,select:[\mean]);
FluidBufFlatten.processBlocking(s,stats,destination:flat);
~analyses.addPoint(i,flat);
"analyzing slice % / %".format(i+1,fa.size-1).postln;
if((i%100) == 99){s.sync;}
};
s.sync;
});
)
(
~umapped = FluidDataSet(s);
FluidUMAP(s,numNeighbours:15,minDist:0.9).fitTransform(~analyses,~umapped,action:{"umap done".postln});
)
~umapped.print;
// normalize
(
~normed = FluidDataSet(s);
FluidNormalize(s).fitTransform(~umapped,~normed);
)
///i would think this would be the place to write audio files, though i'm not exactly sure how it would work.
~normed.dump{|dict|
FluidBufCompose.processBlocking(s, mainBuf,
startFrame,
numFrames,
destination:saveBuffer,
destStartFrame:startFrame,
action:{
saveBuffer.write(
"/Users/a/Desktop/untitled folder/"++i++".aif"); });
};
// fit a kdtree
~tree = FluidKDTree(s).fit(~normed);
// a function to play back and individual slice point
(
~play_slice = {
arg index;
{
var startsamp = Index.kr(~indices,index);
var stopsamp = Index.kr(~indices,index+1);
var phs = Phasor.ar(0,BufRateScale.ir(~src),startsamp,stopsamp);
var sig = BufRd.ar(1,~src,phs);
var dursecs = (stopsamp - startsamp) / BufSampleRate.ir(~src);
var env;
dursecs = min(dursecs,1);
env = EnvGen.kr(Env([0,1,1,0],[0.03,dursecs-0.06,0.03]),doneAction:2);
sig.dup * env;
}.play;
};
)
// plot
(
~normed.dump({
arg dict;
var point = Buffer.alloc(s,2);
var previous = nil;
dict.postln;
defer{
FluidPlotter(dict:dict,mouseMoveAction:{
arg view, x, y;
[x,y].postln;
point.setn(0,[x,y]);
~tree.kNearest(point,1,{
arg nearest;
if(nearest != previous){
nearest.postln;
view.highlight_(nearest);
~play_slice.(nearest.asInteger);
previous = nearest;
}
});
});
}
});
)