[sdiy] audio effects in C??

Gordon JC Pearc e gordonjcp at gjcp.net
Fri Feb 17 23:31:08 CET 2012


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










More information about the Synth-diy mailing list