Audio signal aliasing

I’m trying to do some Delta Sigma/DDS to put out more decent signal than a square wave to my speaker. I haven’t fully understood the theory behind it (my math is quite rusty), but the Wiki page has an image explaining the principle very well and that’s what I tried to emulate:

I’m using a 32 byte look-up table for my sine function and the timer0. I get what I expect from my function:

The whole purpose was to make a cleaner signal than a square wave, but the sound is horrible. I get very annoying distortions, probably because I’m commutating at still audible frequencies. Does anybody know a solution or similar projects?

Here’s my code, it runs on Arduino Leonardo:

#include <util/delay.h>
#include <avr/pgmspace.h>

// waveform look-up table
PROGMEM uint8_t sine32[]  = {128,153,177,199,218,234,245,253,255,253,245,234,218,199,177,153,128,103,79,57,38,22,11,3,1,3,11,22,38,57,79,103};

volatile struct Data 
{ 
    uint8_t counter: 8; // counts from 0 to 255
    uint8_t pwm: 4;     // how many times the pwm value must be kept at 1, from 0 to 8
    uint8_t* waveform;  // pointer to waveform table
} sound;

volatile uint32_t countDown;

void play(uint16_t frequency, uint16_t time, uint8_t* waveform)
{
  sound.counter = 0;
  sound.pwm = 0;
  sound.waveform = waveform;
  
  // set pin 7 as output
  DDRE |= (1 << 6);
  
  // disable timer0 overflow interrupt used for Arduino delay() functions
  TIMSK0 = 0;
  TIFR0 = 0;

  // set mode to PWM, Phase Correct, TOP defined by OCR0A
  TCCR0A = (1 << WGM00);
  TCCR0B = (1 << WGM02);

  // timer0 prescalers
  const uint16_t prescalers[] = {1, 8, 64, 256, 1024};
  // scan through prescalars to find the best fit (ocr <= 255)
  uint16_t prescalerIndex, ocr;
  
  // commutation speed it 256 times the frequency
  frequency = frequency << 8;
  
  // 16MHz / freq / presaler / ocr = commutation frequency
  for(prescalerIndex = 0; prescalerIndex < 5; prescalerIndex++)
  {
    ocr = F_CPU / frequency / prescalers[prescalerIndex];
    if(ocr <= 255)
    {
      // the prescaler and oscillator combination has been found
      break;
    }
  }
  // set the frequency
  OCR0A = ocr;

  // calculare the commutations to reach the playing time
  countDown = frequency * time;

  // reset timer0 counter
  TCNT0 = 0;
  // set the prescaler (enable timer)
  TCCR0B = (TCCR0B & 0xf8) | prescalerIndex;

  // enalble compare interrupt vector
  TIMSK0 |= (1 << OCIE0A);
  
  // wait here until sound is played
  while(countDown);

  // restore timer0 for Arduino time functions
  TCCR0A = (1 << WGM01) | (1 << WGM00);
  TCCR0B = (1 << CS01) | (1 << CS00);
  TIFR0 = (1 << TOV0);
}

ISR(TIMER0_COMPA_vect)
{  
  // slow pwm changes every (frequecy * 32) times
  if((sound.counter % 8) == 0)
  {
    // divide value (0 to 255) by 64 to get an index between 0 and 8
    // adding 16 before shifting makes the singal less "biased" as it is rounded down
    sound.pwm = (uint16_t) (pgm_read_byte_near(sound.waveform + (sound.counter >> 3)) + 16) >> 5;
  }
  
  // fast pwm changes every (frequency * 255) times, which is the frequency of this interrupt
  if(sound.pwm > 0)
  {
    // keep the signal at logic high for the 1/256th of the period
    PORTE |= (1 << 6);
    sound.pwm--;
  }
  else
  {
    PORTE &= ~(1 << 6);
  }
  
  // count repeatedly from 0 to 255
  sound.counter = (sound.counter++) % 255;
  
  if(--countDown == 0)
  {
    // disable compare interrupt and enable overflow interrupt
    TIMSK0 = (1 << TOIE0);
    PORTE &= ~(1 << 6);
  }
}

void setup()
{
}

void loop()
{
  // play 100Hz sine wave for 10 seconds
  play(100, 10000, sine32);
}

You need to low pass filter the output as explained on the WIKI page.

The demodulator can be a simple linear filter (e.g., RC or LC filter) to reconstruct the signal

Pete