[sdiy] audio effects in C??

dan snazelle subjectivity at hotmail.com
Sun Feb 19 04:41:50 CET 2012


thanks a lot for the help

you know, one of the big problems for me is that you mention this as your starting point:

> http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/


that code has a lot of stuff in it that makes very little sense to me


anyone care to help me through it?


it is very dense...many variables have non descriptive names, the comments are pretty sparse, etc.

I would love to get to grips with it though.


here is the code:


-------------

/*
 *
 * DDS Sine Generator mit ATMEGS 168
 * Timer2 generates the  31250 KHz Clock Interrupt
 *
 * KHM 2009 /  Martin Nawrath
 * Kunsthochschule fuer Medien Koeln
 * Academy of Media Arts Cologne

 */

#include "avr/pgmspace.h"

// table of 256 sine values / one sine period / stored in flash memory
PROGMEM  prog_uchar sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

int ledPin = 13;                 // LED pin 7
int testPin = 7;
int t2Pin = 6;
byte bb;




double dfreq;
// const double refclk=31372.549;  // =16MHz / 510
const double refclk=31376.6;      // measured

// variables used inside interrupt service declared as voilatile
volatile byte icnt;              // var inside interrupt
volatile byte icnt1;             // var inside interrupt
volatile byte c4ms;              // counter incremented all 4ms
volatile unsigned long phaccu;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  Serial.begin(115200);        // connect to the serial port
  Serial.println("DDS Test");

  pinMode(6, OUTPUT);      // sets the digital pin as output
  pinMode(7, OUTPUT);      // sets the digital pin as output
  pinMode(11, OUTPUT);     // pin11= PWM  output / frequency output

  Setup_timer2();

  // disable interrupts to avoid timing distortion
  cbi (TIMSK0,TOIE0);              // disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt

  dfreq=1000.0;                    // initial output frequency = 1000.o Hz


*****What is happening here??*****


  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word 

}
void loop()
{
  while(1) {
     if (c4ms > 250) {                 // timer / wait fou a full second
      c4ms=0;
      dfreq=analogRead(0);             // read Poti on analog pin 0 to adjust output frequency from 0..1023 Hz

      cbi (TIMSK2,TOIE2);              // disble Timer2 Interrupt
      tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt 

      Serial.print(dfreq);
      Serial.print("  ");
      Serial.println(tword_m);
    }

   sbi(PORTD,6); // Test / set PORTD,7 high to observe timing with a scope
   cbi(PORTD,6); // Test /reset PORTD,7 high to observe timing with a scope
  }
 }
//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer2() {

// Timer2 Clock Prescaler to : 1
  sbi (TCCR2B, CS20);
  cbi (TCCR2B, CS21);
  cbi (TCCR2B, CS22);

  // Timer2 PWM Mode set to Phase Correct PWM
  cbi (TCCR2A, COM2A0);  // clear Compare Match
  sbi (TCCR2A, COM2A1);

  sbi (TCCR2A, WGM20);  // Mode 1  / Phase Correct PWM
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);
}

//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect) {

  sbi(PORTD,7);          // Test / set PORTD,7 high to observe timing with a oscope

  phaccu=phaccu+tword_m; // soft DDS, phase accu with 32 bits
  icnt=phaccu >> 24;     // use upper 8 bits for phase accu as frequency information
                         // read value fron ROM sine table and send to PWM DAC
  OCR2A=pgm_read_byte_near(sine256 + icnt);    

  if(icnt1++ == 125) {  // increment variable c4ms all 4 milliseconds
    c4ms++;
    icnt1=0;
   }   

 cbi(PORTD,7);            // reset PORTD,7
}



On Feb 17, 2012, at 5:31 PM, Gordon JC Pearc e wrote:

> On 17/02/12 20:59, dan snazelle wrote:
>> Ok lets say I have a  program (on an Avr or pic) that has a few different variables.
> 
> <snip>
> 
> Dan, I hope you don't mind me answering your off-list questions on-list.  If you do, tough, it's a bit late now ;-)
> 
> The reason I want to tackle it on-list is because I want some constructive (hopefully) criticism of my project.
> 
> Firstly take a look at this article:
> 
> http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/
> 
> This is what a lot of my AVR synthesis stuff is based on.  Where possible I tried to keep it in line with the Arduino environment but for the more outré experiments I needed to go to bare metal because things had already hooked ISRs that I needed.
> 
> Okay, now you asked me about fmtoy.  Let's look at that:
> https://github.com/gordonjcp/gyoza/blob/master/fmtoy/fmtoy.pde
> 
> The first few lines define various preprocessor things, and some lookup tables to go into flash including an 8-bit sine and floating point pitch-in-Hz table.
> 
> Next there's a struct that contains patch data, and an array of values that comprise the eight "stock" patches - note that N_PATCH is one less than the number of patches!
> 
> We can skip over lots of horrible global variables.
> 
> set_env() calculates the envelope parameters from the current patch
> set_patch() copies a patch from flash to RAM
> 
> In setup() there is some cruft used when I was driving an analogue resonant filter from fmtoy - yes, it was pretty awesome.  No, it didn't work very well.
> 
> Okay, in the main loop there is a *horrible* buggy MIDI parser that accepts note on, note off, and some continuous controllers.  They are inadequately documented.
> 
> Line 366 to 385 calculate the oscillator pitch, envelope levels and phase and ultimately the timing word for the oscillators
> 
> Line 418 and down is the PWM ISR that actually does the sound generation.  Now from reading the sine DDS article you should know that Arduino pin 11 (PWM2A) is the PWM output and needs to be lowpass filtered and fed to an amp.
> 
> Every 32 times round the loop, we fire the update flag to tell it to update the voice every (roughly) 1ms
> 
> Each operator adds the timing word value to the phase accumulator, and takes the top bits as the pointer to the sine table.  So we calculate the offset into the table from the phase accumulator plus the feedback (or Op1) amount, and wrap by taking it modulo 256 (doing  & 0xff would maybe be faster, if the compiler doesn't optimise this).
> 
> Line 430 calculates the amount of feedback to apply, by multiplying the output, adding the feedback, and shifting right by 8 bits to scale it back down to an unsigned byte.
> 
> Line 441 does a trick to keep the DC offset steady even though we're using unsigned numbers because the AVR8 family only support unsigned int multiply
> 
> Lines 444-447 put it back into a sensible range and ensure that the output value is clipped rather than going off-scale which would cause it to "wrap around" with very objectionable noises.
> 
> Finally, the value is written to OCR2A where it sets the output PWM width, and hence the "DAC" voltage.
> 
> So you asked me:
> 1) Where the output is defined - it's defined in setup() and actually created in the ISR at the end.  For practical purposes, noises come out on pin 11.
> 
> 2) It looks for MIDI on the serial port.  In this case, it actually receives at 57600bps so you will need something to take MIDI and connect to a serial port.
> Grab this: http://www.gjcp.net/~gordonjcp/alsabridge.c and compile it with the instructions at the top of the file.  It's crap but it works.
> You could also hook up an optoisolator and use it with MIDI directly if you set the baud rate.
> 
> 3) You could convert it to look for CV and gate.  Use the analogue inputs for CV (I guess you need to clip to 5V, or scale by 2) and work out the relationship between the input voltage and pitch.  Probably 1024 steps will give you accurate enough pitch tracking.  Use a GPIO pin for gate, and remove all the note queuing stuff from lines 211 to 260.  Then figure out where to handle your CV on in there somewhere.
> 
> Hope this helps.  I welcome any comments or suggestions, but not half as much as I welcome patches ;-)
> 
> -- 
> Gordon JC Pearce MM0YEQ
> 
> 
> 
> 
> 
> 
> 
> _______________________________________________
> Synth-diy mailing list
> Synth-diy at dropmix.xs4all.nl
> http://dropmix.xs4all.nl/mailman/listinfo/synth-diy
> 




More information about the Synth-diy mailing list