ah, inserting the 1 there makes it sound now! i believe previously it worked without, but im happy its eventually such a simple solution, which still i wouldn’t have thought of myself! thank you!
Cool, glad it works now!
That argument got added around May / June, I think, to allow calls to KNearest
to override the parameter set at the object level (we couldn’t do this originally for boring C++ reasons).
hi @tedmoore ,
coming back to this code im again running into the aforementioned error. did you eventually manage to find a workaround for it?
thanks,
jan
Hi @jan,
Sorry this has completely escaped my mind and this thread is now quite long. Can you restate the problem so I can take a look at it?
Thanks,
T
Hi @tedmoore ,
yes, it became long indeed!
Its about the error return in the following block of code:
(i just modified that some data is being read from file, but that shouldn’t alter anything)
// 7. Put the "play info" from all the slices of each in cluster into a buffer
(
fork{
var tmpbuf = Buffer(s);
~ds_play_info=FluidDataSet(s).read("%playinfo.json".format(~data));
~play_info_clusters = {Buffer(s)} ! ~clusters.size.postln;
// ~play_info_clusters = {Buffer(s)} ! ~clusters.keys.maxItem; //alternative suggestion also did not work
~clusters.keysValuesDo{
arg cluster_i, list;
list.do{
arg id, i;
"cluster %\tid %".format(cluster_i,id).postln;
~ds_play_info.getPoint(id,tmpbuf);
s.sync;
// write the first frame to channel 0, frame "i"
FluidBufCompose.processBlocking(s,tmpbuf,startFrame:0,numFrames:1,destination:~play_info_clusters[cluster_i.asInteger],destStartFrame:i,destStartChan:0);
// write the second frame to channel 1, frame "i"
FluidBufCompose.processBlocking(s,tmpbuf,startFrame:1,numFrames:1,destination:~play_info_clusters[cluster_i.asInteger],destStartFrame:i,destStartChan:1);
}
};
s.sync;
// {~play_info_clust_5.plot}.defer;
};
)
returns this:
-> a Routine
18
cluster 63 id slice-72
ERROR: FluidBufCompose: Invalid destination buffer
CALL STACK:
Object:reportError
arg this = "FluidBufCompose: Invalid de..."
Nil:handleError
arg this = nil
arg error = "FluidBufCompose: Invalid de..."
Thread:handleError
arg this = <instance of Thread>
arg error = "FluidBufCompose: Invalid de..."
Thread:handleError
arg this = <instance of Routine>
arg error = "FluidBufCompose: Invalid de..."
Object:throw
arg this = "FluidBufCompose: Invalid de..."
Meta_FluidBufCompose:processBlocking
arg this = <instance of Meta_FluidBufCompose>
arg server = <instance of Server>
arg source = 433
arg startFrame = 0
arg numFrames = 1
arg startChan = 0
arg numChans = -1
arg gain = 1
arg destination = nil
arg destStartFrame = 0
arg destStartChan = 0
arg destGain = 0
arg freeWhenDone = true
arg action = nil
< FunctionDef in closed FunctionDef >
arg id = "slice-72"
arg i = 0
ArrayedCollection:do
arg this = [*151]
arg function = <instance of Function>
var i = 0
List:do
arg this = <instance of List>
arg function = <instance of Function>
Dictionary:keysValuesArrayDo
arg this = <instance of Dictionary>
arg argArray = [*128]
arg function = <instance of Function>
var i = 0
var j = 1
var key = nil
var val = nil
var arraySize = nil
Dictionary:keysValuesDo
arg this = <instance of Dictionary>
arg function = <instance of Function>
< closed FunctionDef >
var tmpbuf = <instance of Buffer>
Routine:prStart
arg this = <instance of Routine>
arg inval = 30052.234579042
-> a Routine
18
cluster 63 id slice-72
ERROR: FluidBufCompose: Invalid destination buffer
CALL STACK:
Object:reportError
arg this = "FluidBufCompose: Invalid de..."
Nil:handleError
arg this = nil
arg error = "FluidBufCompose: Invalid de..."
Thread:handleError
arg this = <instance of Thread>
arg error = "FluidBufCompose: Invalid de..."
Thread:handleError
arg this = <instance of Routine>
arg error = "FluidBufCompose: Invalid de..."
Object:throw
arg this = "FluidBufCompose: Invalid de..."
Meta_FluidBufCompose:processBlocking
arg this = <instance of Meta_FluidBufCompose>
arg server = <instance of Server>
arg source = 452
arg startFrame = 0
arg numFrames = 1
arg startChan = 0
arg numChans = -1
arg gain = 1
arg destination = nil
arg destStartFrame = 0
arg destStartChan = 0
arg destGain = 0
arg freeWhenDone = true
arg action = nil
< FunctionDef in closed FunctionDef >
arg id = "slice-72"
arg i = 0
ArrayedCollection:do
arg this = [*151]
arg function = <instance of Function>
var i = 0
List:do
arg this = <instance of List>
arg function = <instance of Function>
Dictionary:keysValuesArrayDo
arg this = <instance of Dictionary>
arg argArray = [*128]
arg function = <instance of Function>
var i = 0
var j = 1
var key = nil
var val = nil
var arraySize = nil
Dictionary:keysValuesDo
arg this = <instance of Dictionary>
arg function = <instance of Function>
< closed FunctionDef >
var tmpbuf = <instance of Buffer>
Routine:prStart
arg this = <instance of Routine>
arg inval = 30187.001940333
-> a Routine
cluster 63 id slice-72
ERROR: FluidBufCompose: Invalid destination buffer
CALL STACK:
Object:reportError
arg this = "FluidBufCompose: Invalid de..."
Nil:handleError
arg this = nil
arg error = "FluidBufCompose: Invalid de..."
Thread:handleError
arg this = <instance of Thread>
arg error = "FluidBufCompose: Invalid de..."
Thread:handleError
arg this = <instance of Routine>
arg error = "FluidBufCompose: Invalid de..."
Object:throw
arg this = "FluidBufCompose: Invalid de..."
Meta_FluidBufCompose:processBlocking
arg this = <instance of Meta_FluidBufCompose>
arg server = <instance of Server>
arg source = 471
arg startFrame = 0
arg numFrames = 1
arg startChan = 0
arg numChans = -1
arg gain = 1
arg destination = nil
arg destStartFrame = 0
arg destStartChan = 0
arg destGain = 0
arg freeWhenDone = true
arg action = nil
< FunctionDef in closed FunctionDef >
arg id = "slice-72"
arg i = 0
ArrayedCollection:do
arg this = [*151]
arg function = <instance of Function>
var i = 0
List:do
arg this = <instance of List>
arg function = <instance of Function>
Dictionary:keysValuesArrayDo
arg this = <instance of Dictionary>
arg argArray = [*128]
arg function = <instance of Function>
var i = 0
var j = 1
var key = nil
var val = nil
var arraySize = nil
Dictionary:keysValuesDo
arg this = <instance of Dictionary>
arg function = <instance of Function>
< closed FunctionDef >
var tmpbuf = <instance of Buffer>
Routine:prStart
arg this = <instance of Routine>
arg inval = 30243.730297792
thanks,
jan
originally i mentioned it here:
Hi Jan,
Thanks for the reminder! It turns out that the error is because there are some empty clusters. The code was allocating enough buffers for only the clusters that weren’t empty! I’ve replaced ~clusters.size
(which represented only non-empty clusters) with ~kmeans.numClusters
which will be how many KMeans is trying to find. Now there will be a buffer for every cluster index.
I had to change something in step 5 too (assign the KMeans to a variable), so I include the updated code for steps 5-7 below. Let me know if that solves it all for you!
Cheers,
T
// 5. Cluster the MFCCs output
(
~labels = FluidLabelSet(s);
~kmeans = FluidKMeans(s,100).fitPredict(~ds,~labels,{"kmeans complete".postln});
)
// 6. Take out labels information and organize in a dictionary
(
~labels.dump({
arg dict;
~clusters = Dictionary.new;
dict["data"].keysValuesDo{
arg id, cluster;
cluster = cluster[0].asInteger;
if(~clusters[cluster].isNil,{~clusters[cluster] = List.new});
~clusters[cluster].add(id);
};
~clusters.keysValuesDo{
arg k, v;
"points in cluster %: %".format(k,v).postln;
};
});
)
// 7. Put the "play info" from all the slices of each in cluster into a buffer
(
fork{
var tmpbuf = Buffer(s);
~play_info_clusters = {Buffer(s)} ! ~kmeans.numClusters;
~clusters.keysValuesDo{
arg cluster_i, list;
list.do{
arg id, i;
"cluster % / %\tid %".format(cluster_i,~kmeans.numClusters,id).postln;
"\tnumber of buffers in ~play_info_clusters: %".format(~play_info_clusters.size).postln;
~ds_play_info.getPoint(id,tmpbuf);
s.sync;
// write the first frame to channel 0, frame "i"
FluidBufCompose.processBlocking(s,tmpbuf,startFrame:0,numFrames:1,destination:~play_info_clusters[cluster_i.asInteger],destStartFrame:i,destStartChan:0);
// write the second frame to channel 1, frame "i"
FluidBufCompose.processBlocking(s,tmpbuf,startFrame:1,numFrames:1,destination:~play_info_clusters[cluster_i.asInteger],destStartFrame:i,destStartChan:1);
}
};
s.sync;
// {~play_info_clust_5.plot}.defer;
};
)
Hi Ted,
inserting ~kmeans.numClusters makes the block of code work without problems at all.
as i’ve modified the other steps a bit ill let report back if theres anything down (rather, up) the road if inserting your changes… so far this seems to solve it, thank you!
Jan
So there is a little follow up question. Usually i’d write the play info buffers as files for later usage:
~play_info_clusters.size.do{|i| ~play_info_clusters.at(i).write("%%.wav".format(~data,i),headerFormat:"WAV",sampleFormat:"float32")}
this of course returns a lot of errors given the empty buffers being written, e.g.:
File '/Users/jan/Sound/Recordings/pquin/data/5.wav' could not be opened: Format not recognised.
could one write only the non-empty buffers?
Hi @jan,
If the buffer is empty it’s .numFrames
attribute should be nil
so in your loop, check for that and only write it to disk if the .numFrames
is not nil
. There’s even a .notNil
method you can call!
Best,
T