Go Down

Topic: Sound synthesis (Read 2033 times) previous topic - next topic

Horace

I wanted to make a sound synthesizer for Arduino, so I started with a DAC.  I have a 4-bit R-R2 ladder going, and it looks like that will work fine.  Now it's time to expand that to 8-bit and feed it something meaningful.

I'm learning about the timers on the AVR.  If the Arduino has a 16MHz crystal and I use a clock div of 8, that gives a 2MHz clock.  If I configure the AVR to run an interrupt handler every 50 cycles, I would get 40KHz sample rate.  I could also do 100 cycles, for 20KHz.  That would give more cycles to produce output, and both would allow use of the 8-bit timers as well as the 16-bit timer.  It would also allow 100 clock cycles, or 800 CPU cycles to generate the output.

I think this sounds right, tell me if I've gone wrong anywhere in there.

I'm now researching software oscillators and the specifics of implementing the timer.

paulb

I'm really interested in this and will be glad to see you post some code here somewhere.

I wrote a function called freqout that is in the code library - but it's all written in C - using the AVR calls is certainly the way to do this.

Once you've got this figured out it would be nice to see a PWM sine wave function similar to what is available on some other microcontroller environments such as the Basic Stamp.

Horace

I hadn't planned on using PWM and an analog filter.  Using an analog filter, you're limited to a set waveform and that's not exactly taking advantage of the microcontroller's capabilities.  Using a DAC, you're not limited in any way as all waveforms are generated in software.  Sine waves can be generated easily by using a lookup table.  Triangle and sawtooth waveforms are simple maths that can be done at runtime.  Also (and probably most importantly), multiple waves can be mixed and averaged in software with differing amplitudes so true amplitude envelopes with attach, delay, sustain and release can be created.

paulb

I agree with all this it's just that your 4 bit R2R is fairly crude and there aren't 8 pins available (without some complications) on any port so extending to 8 bits is going to be awkward (6 bits is good though). So you're talking about 16 level output,  and the digital "top octave" freq is going to be present in the tones in some quantity.


Horace

Yeah, the 4 bit was just a test.  6 bit would be easy, just shift left 2 bits and write to portd (digital pins 2 through 7).  It's just as easy to grab the 2 highest bits from a byte and shift them to the rightmost 2 bits like (b & 0xB0) >> 6 and write them to the lowest two pins of portb (digital pins 8 and 9).  So it's really not any harder to use 8 bits than it is to use 6 bits.

On my first test, I had the 4-bit DAC on portd, digital pins 0 through 3.  It interfered with the rx and tx pins, but it sure was amusing to actually hear the programs being downloaded over the speaker.

Horace

Anyway, here's some code I use to test the 4-bit DAC.  It can do square and triangle waves, and attempts to do them at 440Hz.  They end up being off because of the CPU cycles used in between.  The square wave will want to pause for 1136uS (half of 1/440), while the triangle wave will want to pause 16 times to represent every possible state.  Because the triangle wave pauses more and because it also does an increment and conditional, its frequency is even more off than the square wave (which is only off by about 3Hz I think).

Code: [Select]

#define CLEAR_DAC  PORTD &= B11000011
#define SET_DAC(x) PORTD |= ((x) & 0x0F) << 2

#define SQUARE
//#define TRIANGLE

void setup() {
 DDRD |= B00111100;
}

/*  Square Wave  */
#ifdef SQUARE
void loop() {
 CLEAR_DAC;
 delayMicroseconds(1136);
 
 SET_DAC(0x0F);
 delayMicroseconds(1136);
}
#endif

/*  Triangle Wave  */
#ifdef TRIANGLE
void loop() {
 int i;
 
 for( i = 0; i < 16; i++ ) {
   CLEAR_DAC;
   SET_DAC(i);
   delayMicroseconds(1136/16);
 }
 
 for( i = 15; i >= 0; i-- ) {
   CLEAR_DAC;
   SET_DAC(i);
   delayMicroseconds(1136/16);
 }
}
#endif

tateu

hey horace! love all that stuff and i'm trying to do the same. i much prefer working with interrupts for better control. you can check this post for that. my code works for atmega8 but someone posted an edit for atmega168.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1167000525

anyway, i'm like you, i don't like pwm and would rather work with a R2R ladder but i don't understand how they work. i did a 4-bit one as well and the output i get is far from ideal. do you get the same kind of stuff? is it what we're supposed to work with? i triple-checked the wiring and it's right... let me know if you have a trick to get the ladder working better.

bits       V OUT

0       0.00  
1       2.49
2       3.00
3       3.73
4       3.33
5       3.98
6       4.03
7       4.34
8       3.57
9       4.15
10       4.21
11       4.47
12       4.22
13       4.49
14       4.51
15       4.65

pha555

tateu,

I think you simply have your four bits backwards.

Consider;

V_out = 5.0 * (B3 / 2 + B2 / 4 + B1 / 8 + B0 / 16)

Note that for a count of one, the voltage is 1/16 of 5.0.  The fact that you have 2.5 or 1/2 of 5.0 suggests you have Bits 3 and Bits 0 reversed.

Best wishes.

P H Anderson

Horace

pha555 got it.  An R-R2 ladder is really simple.  Just think of it this way, the least significant bit passes through the most resistors, so it adds the least to the total voltage.  The next bit passes through less resistors, and adds roughly twice as much to the voltage as the previous bit.  Your bit 1 looks like the most significant bit as it provides roughly half of the maximum voltage.

Also, an R-R2 ladder made with carbon film resistors isn't going to be very accurate.  Most are 10% or 5% accurate (gold or silver fourth stripe) so there will be errors.  Since I'm using mine for sound output, that just adds some "quality" to the sound, so it'll probably end up being a plus anyway.  You can get ladder ICs that are a lot more accurate (and much more handy to work with).

tateu

Thanks to both of you (PH and Horace) for the answers. but there is still a couple of issues.

- I got your point on the MSB vs LSB but in the end, I have all the possible combinations of 4 bits and never get anything under 2.5V (I guess my value 8 = 1000 would then be equivalent of the value 1 = 0001 if I have it backwards and it still spits out 3.57V).
I use the schematics here for my ladder - is this right? (4 bits instead of 5 of course)
http://en.wikipedia.org/wiki/Resistor_Ladder

- the other issue is that the outputs are not in continuous order 3>2 but 4<3 etc.
Note that out of deep dispair, I tried the ladder outside of the arduino envireonment to rule out a software pb and did it manually with a 4-position dipswitch connected to 5V and got the same result.

>> do you have a schematics of your ladder? is it the same as the one in wikipedia?

>> finally, if you have a link to those ladder ICs you mentionned? sounds great.

Horace

My schematic is the same as in the wikipedia article.  I haven't actually measured the voltages, but with my crude sound card oscilloscope, my waveforms look correct.

As for the ICs, I've never used one so I can't recommend any.  I have searched for them before, and I seem to remember coming up with a few.  There are also slightly more complicated DAC chips that work on roughly the same principal.  Look for DACs on digikey and you'll find more options than you know what to do with.

I'll be sticking with my ghetto resistors though, even if they are a pain to assemble and not terribly accurate.

tateu

yes i like the lo-fi aspect of the resistor ladder. if you can think of anything that might help or if you can send me what type of output you get with what code, i'd love to see it. i'm at tateu@yahoo.com.
thanks again for the help.

blen2r

Hi,

I'm interested in sound synthesis as well but I know next to nothing about building synths (but I know how to use them).

Do you know some good websites/books/anything about this topic?

Thank you!

mem

I have not been following this thread,  but if you have not already seen it, have a look at this excellent software based Arduino synth : http://code.google.com/p/tinkerit/wiki/Auduino

blen2r

Thank you, I will definitly look into that!

Go Up