>>35
I wrote one back in 2003.
It's as easy as you think.
Some junk like:
audio[i] = sin((freq * i * 2 * M_PI / SAMPLE_RATE) * normalize(mod_signal[i]))
or whatever. I didn't check that so you should, or wait for someone else to go full retard on me for leaving out the semicolon and they'll probably catch the meaningful mistakes while they're at it. Convert it to LUTs and add AA/interpolation if you like (probably best for FM.) normalize() makes an element of audio[] suitable for use as a modulation signal, and exactly how it works is dependent on your data type.
For primary operators, initialize an empty modulation signal buffer to whatever is neutral and use the same effect. This way you can feedback into the same operator by writing to the init'd mod buffer.
Speaking of data types, use floats with DC0 = 0. Least of all benefits of this is that simply zeroing the mod buffer will be correct initialization.
Oh, I almost forgot:
#define SEMITONE_RATIO (1.0594630943592)
freq = pow(SEMITONE_RATIO, midi_note_number)
I think that's right for the midi spec but I can't remember. For some reason I have it split up like this in some code I have laying around:
r = note%12;
q = note/12;
f = pow(SEMITONE_RATIO, r);
f *= pow(2, q -4);
... probably using those extra values for some other thing but I can't be arsed to check.
There you go. Route those into each other according to whatever crazy idea you have and do ADSR (sample data multiplier maps) on the 'key' events.
If you are tempted to use LADSPA plugins for any reason, and happen to be operating in stereo but are stuck with a mono effect:
M = (L+R)/2;
S = (L-R)/2;
L = M + S;
R = M - S;
L and R being left and right channels, M (mid) being the mono signal and S (side) being the stereo phase signal. Run the mono process on M and take the output as M', combine M' with S to get the (processed) L' and R' values. Not for use with effects that demean the stereo image.