There’s not much documentation about this, but I took a quick look at the source code to find out.
Loading the buffers uses a server command, /b_allocRead. This is a “sequenced command,” meaning it’s asynchronous, and they are executed one by one in a queue. That is, you can dump a hundred /b_allocRead-s into the queue, and the server will step through the queue until they’re all finished.
The server status bar uses a command /status. This is also a sequenced command.
So I think what’s happening is:
- Your code dumps a hundred allocRead requests into the queue.
- A fraction of a second later, the IDE asks for the server’s /status. … But this request goes at the end of the queue, after all of the allocReads.
- So… the server has to finish reading all the buffers before answering the /status request.
One way to handle this is to accept it, and just wait for it to finish.
Another way is to chunk the buffer loads. It isn’t immediately obvious how to do that, but this is what I’d do. By sending 5 requests, then waiting, then 5 more etc., there are brief windows where the IDE can slip in its ‘/status’ request.
(
fork {
var chunkSize = 5;
// countdown: number of requests to send before waiting
var requestsPending = chunkSize;
// countdown: how many uncompleted reads remain
var pending = chunkSize;
var cond = CondVar.new;
var num = 100;
~final = num.collect {
var startFrame, dur = 1, select = (~newfolder.size).rand;
var buf;
startFrame = ~newfolder[select][1].rand;
dur = dur * 44100;
buf = Buffer.read(s, ~newfolder[select][0].fullPath.asString,
startFrame, dur, action: {
// when one request finishes,
// drop the count
pending = pending - 1;
// and see if it's OK to continue
cond.signalAll;
}
);
// just sent a request, so one less is pending
requestsPending = requestsPending - 1;
// no more requests for this chunk
if(requestsPending == 0) {
// will not advance past this point
// until after the 'chunkSize' pending requests have cleared
cond.wait { pending == 0 };
requestsPending = chunkSize;
pending = requestsPending;
};
buf // loop should return the buffer
};
"done".postln;
}
)
BTW:
SoundFile.openRead(x.fullPath.asString).numFrames
One issue here is that you’re opening files without closing them, causing file handles to accumulate in the language. Better practice is to close a file when you’re finished with it.
Actually, in SoundFile, the header properties are still available after closing the file, so you can just do SoundFile.openRead(x.fullPath.asString).close.numFrames
.
EDIT: First version of the code block didn’t handle the return value from each loop cycle correctly – fixed.
hjh