Having a precalculated look up table for every octave, should be no performance problem.
I don't know if it's off any help, but I have implemented a sine wavetable oscillator (calling sin(x) every sample is slower than using this method).
At startup I fill the array:
for(int i = 0; i < 2048; i++)
sinTable[i] = sinf(i * float_Pi / 1024.0f);
and in my SynthesiserVoice's renderNextBlock() method I do the following:
while (--numSamples >= 0)
int index = (int)voiceUptime;
float v1 = sinTable[index & 2047]; // This is a little hack to prevent modulo calculation
float v2 = sinTable[(index +1) & 2047];
// Basic linear interpolation
const float alpha = float(voiceUptime) - (float)index;
const float invAlpha = 1.0f - alpha;
const float currentSample = invAlpha * v1 + alpha * v2;
// Fill the buffer
voiceBuffer.setSample (0, startSample, currentSample);
voiceBuffer.setSample (1, startSample, currentSample);
// advance the sample counter
jassert(voicePitchValues[startSample] > 0.0f);
voiceUptime += (uptimeDelta * voicePitchValues[startSample]);
The voicePitchBuffer are precalculated pitch values for the current audio buffer (it is calculated just before this method is called.
This is working quite well and is the basic concept of my modular design (I can add as many modulators / envelopes / filters I want). I know there is some overhead which I have to introduce to gain the flexibility, but I think this is how most modular systems are done.
But I also strongly recommend using a profiler (VerySleepy does the job). I have squeezed out another 20% - 30% performance gain by doing so.
There are some other general tips I picked up somewhere in the interweb:
- don't use virtual functions for a per sample function (like tick() or calculateNextSample()). The overhead of carrying the vtables around is sometimes noticable (and sometimes not, but in my case it was).
- try to avoid calling complex mathematical functions on a per sample basis (like exp, sin, sqrt, pow). Of course sometimes they are needed, but in most cases there is a clever guy who came up with a solution for this by using only multiplication and addition. musicdsp.org is a great place to search for this stuff.
- Try to vectorize as much as possible (the FloatVectorOperations come in handy for this)
I don't know if I am preaching to the choir here, but maybe it is of some help.