Actually, the API allows for both, whichever suits your needs. When doing buffer based processing, you can even add advanced automation, etc.
This is a design choice to make implementing new effects simple, and the framework providing this extra functionality for you.
//api-buffer-effect
self.effects[n].pushSample(buffer[i + n], 0);
//api-generator
out[i + n] = this.getMix(n) * this.mix + buffer[i + n];
This is very different from being able to process batches of samples within your effect or osc code -- even if the JIT inlines the functions of this.mix, you will still incur unnecessary setup cost.Of course, without profiling this is just speculation.
However, I should probably set up some public performance tests and compare the instructions these things compile to have some hard data back my claims, I wouldn't exactly trust me just saying it is so, as I have just tested these things on the fly.
But, however, this approach is more modular, and fits more use cases, and that matters even more for me right now, but trust me, I've spent my time optimizing every operation to the point that it doesn't make things harder to use. :)
I would love to see your performance benchmarks.