Arduino Polyphonic Synth

EDIT: See the last post for the most current info. I just kept it in the same thread.

So I've learned to use the internal timers on the arduino, and I've gotten it to make 8 bit noises using PWM and a lowpass filter. So, I built a MIDI synth! Hardware is super simple, just an RC lowpass filter connected to pin 11. (I can't exactly remember what values) One timer is set up for fast PWM on pin 11, another timer updates the compare register for the first timer at the correct frequency. It can play any 16-step (could be more or less, 16 just seemed like a good number) 8 bit waveform, like sawtooth, square, or triangle. Here's the code:

#include 
#include 

//  A MIDI simple monophonic synth, with wavetable synthesis.
//  Uses timer2 to generate PWM representing an analog output.  A simple RC lowpass filter
//  filters to an analog output.  (in the initial setup, R=100ohm  C=0.33uF
//
//  Eventually, the tone may be controlled in a timer interrupt routine
//  For now, manually coded in loop()

const int notes[] = {
  NOTE_B0, NOTE_C1, NOTE_CS1, NOTE_D1,    // other octaves by multiplying by power of 2
  NOTE_DS1, NOTE_E1, NOTE_F1, NOTE_FS1, 
  NOTE_G1, NOTE_GS1, NOTE_A1, NOTE_AS1, 
};

byte waves[][16] = {
  {
  0x00, 0x20, 0x40, 0x60, 
  0x80, 0xa0, 0xc0, 0xe0, 
  0xff, 0xe0, 0xc0, 0xa0, 
  0x80, 0x60, 0x40, 0x20
  }
  ,
  {
  0xff, 0xff, 0xff, 0xff, 
  0xff, 0xff, 0xff, 0xff, 
  0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00
  }
  ,
  {
  0xff, 0xee, 0xdd, 0xcc, 
  0xbb, 0xaa, 0x99, 0x88, 
  0x77, 0x66, 0x55, 0x44, 
  0x33, 0x22, 0x11, 0x00
  }

};
//  Triangle wave, just wanted something different from the typical square wave.

MIDI_Class input;
int currentNote;
long currentPeriod;
int currentIndex;
unsigned long lastToggle;
int currentWave = 0;

void setup()  {
  pinMode(11, OUTPUT);  //set OC2A pin to output

  TCCR2A |= 1 << WGM20;  //     \
  TCCR2A |= 1 << WGM21;  //   }- Set timer to phase fast PWM mode
  TCCR2B &= ~(1 << WGM22);  //  /  

  TCCR2A |= 1 << COM2A1;  //      }- Set to non-inverting PWM
  TCCR2A &= ~(1 << COM2A0);  //  /

  TCCR2B |= 1<< CS20;  //      \
  TCCR2B &= ~(1 << CS21);  //   }- Set to prescalar of 1 (no prescalar).
  TCCR2B &= ~(1 << CS22);  //  /           62500 Hz PWM

  //============================================================================

  //Setting up timer1 for CTC mode
  TCCR1A &= ~(1 << WGM10);  
  TCCR1A &= ~(1 << WGM11);
  TCCR1B |= 1 << WGM12;
  TCCR1B &= ~(1 << WGM13);

  //Prescalar 1
  TCCR1B |= 1<< CS10;
  TCCR1B &= ~(1 << CS11);
  TCCR1B &= ~(1 << CS12);

  TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt 
  sei();

  input.begin();  //initialize MIDI input
  
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
  pinMode(3, INPUT);
  digitalWrite(3, HIGH);

}


void loop()  {
  int count = 0;
  if(digitalRead(2) == LOW)  {
    count++;
  }
  if(digitalRead(3) == LOW)  {
    count++;
  }
  currentWave = count;
  
  
  //Midi input handling

  if(input.read() == true)  {  //do we get signal
    if(input.getType() == NoteOn && input.getData2() != 0)  {  //is it a noteOn event,
      currentNote = input.getData1();                          //  and not with 0 velocity?

      int noteIndex = (currentNote - 23) % 12;  //figure which value in note array corresponds to
      //  recieved MIDI note
      int noteOctave = (currentNote - 23) / 12; //figure out what octave the note is
      unsigned long Hz = notes[noteIndex] * (1 << noteOctave);
      wOCR1A(hz2ocr(Hz * 4));
      wTCNT1(0);


    }
    else if(input.getType() == NoteOff || input.getData2() == 0)  {  //is it a NoteOff event,
      if(input.getData1() == currentNote)  {                         //  or 0 velocity NoteOn?
        currentNote = 0;
      }
    }
  }

  //  End of midi input handling



  if(currentNote != 0)  {
    TIMSK1 |= 1 << OCIE1A;
  }
  else  {
    TIMSK1 &= ~(1 << OCIE1A);
    OCR2A = 0;
  }


}


unsigned int hz2ocr(unsigned long hertz)  {
  unsigned long ocr = (16000000L / (hertz *2)) - 1;
  return int(ocr);
} 


ISR(TIMER1_COMPA_vect)  {
  currentIndex = (++currentIndex) % 16;
  OCR2A = waves[currentWave][currentIndex];
}

void wOCR1A(unsigned int value) {
  unsigned char sreg;
  
  /* Save global interrupt flag */
  sreg = SREG; 

  /* Disable interrupts */
  cli();

  /* Set TCNT1 to i */
  OCR1A = value; 

  /* Restore global interrupt flag */
  SREG = sreg;
  
  sei();
}


void wTCNT1(unsigned int value) {
  unsigned char sreg;
  
  /* Save global interrupt flag */
  sreg = SREG; 

  /* Disable interrupts */
  cli();

  /* Set TCNT1 to i */
  TCNT1 = value; 

  /* Restore global interrupt flag */
  SREG = sreg;
  
  sei();
}

frequencies.h is a file with #defines for all the note frequencies. It is copied and pasted from those found in the tone library, so including the tone library would work. In the current rough state of the synth (stuff haphazardly put into a breadboard) different waveforms are selected by connecting pins 2 or 3 to ground. 0 pins connected, triangle. 1 pin, square. 2, sawtooth.

A song snippet I made while playing around with the synth and my kp3: song

And hopefully soon to come: http://www.youtube.com/watch?v=AtBuGlE_FVM Original video got stuck processing. Reuploaded, fixed.

Really nice sound! If you ever find out the values for the rc circuit, please post them.

Okay, I checked out the circuit,and
R=100ohm
C=0.33uF

And a 100uF dc blocking cap directly after the filter, before the output jack.

I apologize if I sound dense, but is the wiring (both of the parts and to the speaker) complicated?

Not at all complicated!

All it was (I've made progress on putting it inside the enclosure, it's no longer on the breadboard) was Arduino pin 11 -----/\/\/---------*-------------| |--------------------1/4 inch jack ---->> mpc or kp3 resistor | DC blocking cap | | | = filter cap Ground for jack | Ground

Hopefully my ASCII schematic does not get messed up!

Was that entire song demo done with it? Regardless, it's catchy... :)

sciguy:
Not at all complicated!

Thanks - I will have to put one together

Was that entire song demo done with it?

No, the drums and looping are from the kaoss pad, and the compressor is the mpc. It was just something I did when I was bored and decided to play around with it. The synths in the video's music are also the arduino synth, run thru the kaoss pad for effects.

Oh, and so far, I have everything wired up in the enclosure except the audio circuitry. So it has an external USB port, power jack and switch, MIDI in/out/thru jacks, with a switch to connect or disconnect the midi serial lines. And an 8*16 RG led matrix, and 6 pots. And in the future, 6 buttons.

So I made some not apparently relevant progress on the synth. I've been working on the graphics side of it, the 8*16 led matrix.

As of now, it can do sprite manipulation, with a function that takes the sprite data and a pair of coordinates and displays the sprite at those coordinates. And, which I'm more proud of, it can draw lines between any two given points on the screen! (or off the screen, it just doesn't show all of it)

All from scratch, no help from teh internets (I found out about the Bresenham line algorithm after I made the code. I unknowingly recreated the algorithm in my code before I had even heard of it! :roll_eyes:)

I'll post the code once I have some little bugs fixed, but in the meantime I'll post a video! http://www.youtube.com/watch?v=X6L4a3UT9qw

More Progress!!!

I added 2 1/4 inch jacks, one for the audio output, one for something else in the future, meybe a cv output, i dunno.

So, I have a fully working simple midi synth inside the plastic enclosure! Selectable waveform by the first knob. I still have to work out a couple bugs. The main issue right now is that for some reason, only the square wave is outputted correctly. The triangle has a weird peak where it should be at its lowest point, and the saw only seems to output the first few steps of the waveform, then it zeroes out.

Fixing that will be for another day, I'm happy with the progress for now.

By the next time I post (unless consulting for a problem) I will have a (hopefully polyphonic) 8bit synth with a GUI!

Update:

I lied, I don't have a working synth with gui yet, because I'm having some problems with MIDI input. But I finally went to radioshack to get some more knobs, so now it has knobs on all 6 pots. I also got some buttons, so now it has 6 buttons, 4 in a d-pad orientation to the left of the screen, and 2 larger buttons to the right of the screen. So in addition to making a synth with audio generation capabilities of a gameboy, I could have a little gamesystem that runs on a 2 bit color 8*16 display!

very nice project !!!

"(°_°)"

Keep the updates coming! I'm interested to see where you are going with the screen implementation.

I'm working on getting polyphony an arpeggiation right now, so no screen yet.

But I'm a bit stuck on a bit of code... :( (see my topic under audio about me being puzzled over a bit of code)

Still haven't made progress on the audio code, still stuck on the same problem. (here: problem?)

But I rewired the led matrix shield some (wirewrapping ftw) changing some pins, and now all 6 shift registers are daisychained and controlled thru hardware SPI, for extra speed. This also means that I can use SPI to interface to a parallel-in, serial-out register for button inputs.

Thankfully, this practically does not interfere with the rest of the code at all, because the other OC pin for timer2 is pin 3, I'd just have to change the timer configuration a bit to use the B half of timer2.

Alright, HUGE progress!

I went from using 2 timers for monophonic sound, to using only one timer for 4 part polyphony!

I haven't written the midi handling code yet to handle polyphony, but the synth is capable of playing 4 notes.

Right now it plays the root note (as sent by the midi keyboard), a major third, a perfect fifth, and an octave. I just chose these notes arbitrarily, it's not limited to certain intervals or notes, it's just a test for now.

Here's a sound sample: POLYPHONY WOOO

I can officially say this arduino synth have surpassed the audio production capabilities of a gameboy!

Very nice.

I´ve just ordered my Arduino to start playing with stuffs like that. I was feeling very limited doing sequencers with analog compnents such as CMOS. Anyway i did make a good Atari Punk Console like sequencer that had some good sounds to it but it uses so much electronics. I guess the road to synthesizers is really throuh uC.

Anyway keep posting with improvements as I am looking foward to see them. :P

A little progress today, and I filmed a simple demo of the synth so far. I got the arduino doing sprite-based graphics (to display numbers) at the same time it's acting as a MIDI polyphonic synth. The 4x4 characters that I made for it to display are convenient since each can be stored in a single unsigned int.

There are 4 numbers on the screen, each turns on when a corresponding voice on the synth is playing. Songs: Dr wily stage 1 theme, megaman 2; UN owen was her, embodiment of scarlet devil. http://www.youtube.com/watch?v=o7_udMf-5h8

Blimey, that looks pretty neat.

I dunno if you'd be interested, but I've put up some code for an 8 voice + 1 filter synth that I'm building - see the thread below. http://arduino.cc/forum/index.php/topic,80569.0.html

The oscillator etc. code is hacked together in assembler to be extremely efficient, whilst using a nice 256 byte wavetable, and with 64 volume levels per oscillator for nice polyphonic playback.

I really need to get a nice box sorted for mine - that looks so much cooler with the lovely well built box. Hmm.

Joe

joemarshall: Blimey, that looks pretty neat.

I dunno if you'd be interested, but I've put up some code for an 8 voice + 1 filter synth that I'm building - see the thread below. http://arduino.cc/forum/index.php/topic,80569.0.html

The oscillator etc. code is hacked together in assembler to be extremely efficient, whilst using a nice 256 byte wavetable, and with 64 volume levels per oscillator for nice polyphonic playback.

I really need to get a nice box sorted for mine - that looks so much cooler with the lovely well built box. Hmm.

Joe

Thanks, and well done on your project. I would look at the code, but I like figuring things out on my own! :)

I was thinking about rewriting my ISR in assembly for speed, I might get around to that sometime. First I'd have to learn assembly... :cold_sweat:

The 16 byte wavetable was a bit arbitrary, I could easily set it to do more (within the frequency limits of my code; I would probably just have it step by powers of 2 for higher frequencies) but I just haven't made up the larger wavetables. I just typed up some hex values for triangle, sawtooth, and square waves, and I didn't feel like doing more than 16 bytes each. :roll_eyes:

Plans I have for it: Hardware — make a new better audio board Software — a lot planned. customizable software midi routing, envelopes on each voice, a built in sequencer, to name a few things.