Question re: polyphonic ADSR generator (CV output).

Hey guys.

So I'm new to microcontrollers (and pretty useless with C, heh). But I received my Uno in the mail and finally got cracking last week on what I thought would be a useful beginner project. I'm a modular synth guy, so for me a polyphonic ADSR envelope generator would be really useful. As in, it has eight inputs for gate signals, eight independent envelopes out, and one set of ADSR knobs. Also awesome would be the ability to emulate the response curves of certain hardware platforms.

Not sure if this would be better suited for the general approaches forum? Anyway the code I'm going to be referring to is up on github -- https://github.com/rmosquito/PolyEGg .. drop me a line if you want commit access?

A little bit of thinking led me to realize that using a DDS implementation was really only the way to go for this; but instead of looping through the accumulator it just kicks into the next envelope stage on overflow. Each stage checks for a gate signal and responds accordingly; retriggers and stuff are accounted for (so reapplying a gate signal during the release stage scales correctly, etc.). This led to a good amount of conditional checking. I'm using an external (SPI) DAC, btw. (I really want eight envelopes at high output levels and I'm willing to spend a couple extra bucks to do it easily.)

Anyway, I wrote the thing and in principle it works. I.e. the curves look okay in the scope, and it handles gates as expected. The big gotcha is that nothing's timed, and uh, this gets into the meat of my question.

How do I make the timing consistent? I see three options:

  1. Put pretty much the whole thing -- messy conditional checks and all -- into an ISR. This goes against what little I know about how ISRs should be used.
  2. Just watch micros() and hold off iterating to the next loop through until the timer exceeds... whatever. This seems ghetto but would probably be better than 1.
  3. Create some sort of buffer, and push the bytes I want to write to my DAC into that buffer. Then use an ISR to quickly read from the buffer and write to the DAC. This seems the most elegant and most precise in terms of timing, but I have zero zero zero idea how to keep from filling my buffer (well, buffers, I guess I'd need eight) with stale data? Do I just have one value in the buffer and keep overwriting it?

So... any suggestions on how to best approach this? Would option 2 going to serve me just as well as 3? Is there nothing to fear with option 1? Is there a mysterious option 4 I never considered?

Thanks everyone!

  • RM

what Dac are you using?