Well, the whole thing advanced a lot. I'm using all pins on port D, so to send note events I use another board I2C connection. The idea is to use an ATmega328 at 20Mhz on its own Shield when its done.
So far I got 50khz, 8 voices, PWM modulation and double-voice with deviation, it sounds PHAT. ;-)

I removed one check and just let the position overflow by itself. So I could use MULT as 65535 and MULT2 as 65535/2 and also modulate the Pulse Width.
Its not ready yet, but once it is, a single chip will get a nice 8 voice duo-note output. Still miss filters and envelopes, but that will be added on the XT version, this is just the LE version. ;-)
#include <Wire.h>
float freqtab[128];
#define MULT 65535
#define MULT2 (65535/2)
#define MTYPE unsigned int
#define MAX_V 8
#define I2C_ADDRESS 4
MTYPE oscPos[MAX_V];
MTYPE oscRate[MAX_V];
MTYPE oscPWM = MULT2;
uint8_t outPins = 0;
uint8_t voiceNote[MAX_V];
uint8_t voiceOrder[MAX_V];
uint8_t voiceOrderCounter = 0;
uint8_t voiceActive[MAX_V];
// ======================================================================================= //
void setup()
{
memset(oscPos,0,sizeof(oscPos));
memset(oscRate,0,sizeof(oscRate));
memset(voiceNote,0,sizeof(voiceNote));
memset(voiceOrder,0,sizeof(voiceOrder));
memset(voiceActive,0,sizeof(voiceActive));
double k = 1.059463094359; // Frequency (Hz) Table
double a = 6.875;
a *= k; a *= k; a *= k;
for (int i = 0; i < 128; i++) { freqtab[i] = (float)a; a *= k; }
TCCR1A = _BV(WGM11);
TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS10);
ICR1 = 300-1;
pinMode(0, OUTPUT);
pinMode(1, OUTPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
TIMSK1 = _BV(TOIE1);
sei();
Wire.begin(I2C_ADDRESS);
Wire.onReceive(receiveEvent);
}
// ======================================================================================= //
uint8_t isDecay = 1;
uint8_t pwmModRate = 1;
uint8_t pwmModRateCounter = 0;
uint8_t pwmModAdder = 8;
#define calcOSC(a) oscPos[a] += oscRate[a]; if (voiceActive[a] == 1 && oscPos[a] < oscPWM) bitSet(outPins,a);
// ======================================================================================= //
ISR(TIMER1_OVF_vect)
{
PORTD = outPins;
outPins = 0;
calcOSC(0);
calcOSC(1);
calcOSC(2);
calcOSC(3);
calcOSC(4);
calcOSC(5);
calcOSC(6);
calcOSC(7);
pwmModRateCounter++;
if (pwmModRateCounter > pwmModRate)
{
pwmModRateCounter = 0;
if (isDecay == 1)
{
oscPWM -= pwmModAdder; if (oscPWM < (MULT2/100)) isDecay = 0;
}
else
{
oscPWM += pwmModAdder; if (oscPWM >= MULT2) isDecay = 1;
}
}
}
// ======================================================================================= //
void loop()
{
//
}
// ======================================================================================= //
void receiveEvent(int howMany)
{
while(Wire.available() > 0) // loop through all but the last
{
char c = Wire.receive(); // receive byte as a character
if (c > 0) setNoteOn(c); else if (c < 0) setNoteOff(c*-1);
}
}
// ======================================================================================= //
void setNoteOn(uint8_t note)
{
uint8_t voice = 255;
for (char v=0; v<MAX_V/2; v++)
{
if (voiceNote[v] == 0)
{
voice = v;
break;
}
}
// All voices used, steal oldest one //
if (voice == 255)
{
uint8_t order = 255;
for (char v=0; v<MAX_V/2; v++)
{
if (voiceOrder[v] < order)
{
order = voiceOrder[v];
voice = v;
}
}
}
// Store note //
voiceOrderCounter++;
voiceNote[voice] = note;
voiceOrder[voice] = voiceOrderCounter;
// Set Output //
oscRate[voice] = (MTYPE) MULT * (1.0f/53333.333f) * freqtab[note];
voiceActive[voice] = 1;
uint8_t deviation = 1;
if (note > 48) deviation = ((note-48)/4)+1;
oscRate[voice+4] = oscRate[voice] + deviation;
voiceActive[voice+4] = 1;
}
// ======================================================================================= //
void setNoteOff(uint8_t note)
{
for (char v=0; v<MAX_V/2; v++)
{
if (voiceNote[v] == note)
{
voiceActive[v] = voiceActive[v+4] = 0;
voiceNote[v] = 0;
oscRate[v] = 0;
oscRate[v+4] = 0;
break;
}
}
}