Hey guys,
I need to generate some sound data in realtime to fill a buffer which is being played by an interrupt which sends the data out to my DAC. I think I've got the keeping the buffer filled part down, and the DAC update interrupt workds fine. But now I need to do my additive synthesis in realtime and combine sine waves as needed.
I decided to start small and just get a single 4000hz tone up and running, but I'm looking at the math, and I'm thinking there's gotta be a faster way to calculate the index into the sine table which I need to use for the current sample.
Here's the code I've been working on:
frequency = 4000; // Set frequency of sine wave we wish to generate.
blah = SAMPLERATE/frequency; // Calculate number of samples per complete sine wave at this frequency. (31250/4000 = 7.8125)
blah2 = fmod(currentSample, blah); // Divide samples played to this point by number of samples per copmplete sine wave, and return remainder. Result will be between 0 and blah.
blah3 = blah2/blah; // Normalize blah2. Blah3 will be a number 0..1 (actually, always less than one) which represents where along one complete sine wave we are now at.
blah4 = blah3*SINETABLESIZE; // Calculate index of value to pull from sine table.
blah5 = pgm_read_byte(sintable+blah4); // Pull value from sine table.
newSample = blah5 * volume; // Multiply sine table value by amplitude of the wave we want to generate. Volume is 0..1.
SAMPLERATE = 31250. And SINETABLESIZE = 256. The sine table is a table of bytes, and is offset by 127.
currentSample is an index which I increment for every sample I add to the buffer. Think of it like a millisecond timer. Except instead of being incremented by 1000 every second, it's incremented by 31250, which is my samplerate.
Anyway, I need to add up to five different sine waves at once plus some random noise, and do that 31250 time a second, plus I'll have to modulate the volume at the same time. That's why I figure I need to get this bit of code which generates a particular sample for a particular sine wave at a particular volume as fast as possible. I'm pretty sure there's a way I can get rid of that floating point arithmetic there, but it's giving me some trouble so I thought I'd see if anyone had any insights.
I probably screwed up newSample there too since I'm multiplying it by volume before I convert it back to a signed value. As it is it would end up being 0...255 not -128 to 127 like it should probably be.