Stereo Arduino (Help)

Hey I'm trying to get my Arduino (Diecimila) to play multiple melodies as the same time using PMW and digital writes. I tried to modify a sketch by D. Cuartielles and failed miserably.(I'm new to the Arduino) So if you can help me fix my modified code it would be great! Any thing with an "R" of "r" after it indicates my try at modifying a second second audio channel into the code.

Thanks,

Dragonos

// TONES  ==========================================
// Start by defining the relationship between 
//       note, period, &  frequency. 
#define  bb    4050    // 261 Hz 
#define  c     3830    // 261 Hz 
#define  d     3400    // 294 Hz 
#define  e     3038    // 329 Hz 
#define  f     2864    // 349 Hz 
#define  g     2550    // 392 Hz 
#define  a     2272    // 440 Hz 
#define  b     2028    // 493 Hz 
#define  C     1912    // 523 Hz 
// Define a special note, 'R', to represent a rest
#define  R     0

// SETUP ============================================
// Set up speaker on a PWM pin (digital 9, 10 or 11)
int speakerOutl = 9;
int speakerOutr = 10;

// Do we want debugging on serial out? 1 for yes, 0 for no
int DEBUG = 1;

void setup() { 
  pinMode(speakerOutl, OUTPUT);
  pinMode(speakerOutr, OUTPUT);
  if (DEBUG) { 
    Serial.begin(9600); // Set serial out if we want debugging
  } 
}

// MELODY and TIMING  =======================================
//  melody[] is an array of notes, accompanied by beats[], 
//  which sets each note's relative length (higher #, longer note) 
int melody[] = {  d,R,d,R,d,R,d,R, f,R,f,R,f,R,f,R, e,R,e,R,e,R,f,R, c,R,c,R,c,R,c,R,     d,R,d,R,d,R,d,R, f,R,f,R,f,R,f,R,     g,R,g,R,g,R,a,R, e,R,e,R,e,R,e,R,};
int beats[]  = { 3, 1,3,1,3,1,3,1, 3, 1,3,1,3,1,3,1, 3, 1,3,1,3,1,3,1, 3, 1,3,1,3,1,3,1,  3, 1,3,1,3,1,3,1,3, 1,3,1,3,1,3,1,    3, 1,3,1,3,1,3,1,    3, 1,3,1,3,1,3,1,}; 
int MAX_COUNT = sizeof(melody) / 2; // Melody length, for looping.

int melodyr[] = {  d,f,e,c,d,f,g,e,};
int beatsr[]  = { 32,32,32,32,32,32,32,32,}; 
int MAX_COUNTr = sizeof(melodyr) / 2; // Melody length, for looping.

// Set overall tempo
long tempo = 20000;
// Set length of pause between notes
int pause = 1000;
// Loop variable to increase Rest length
int rest_count = 100; //<-BLETCHEROUS HACK; See NOTES

// Initialize core variables
int tone = 0;
int beat = 0;
long duration  = 0;
int toner = 0;
int beatr = 0;
long durationr  = 0;

// PLAY TONER  ==============================================
// Pulse the speaker to play a tone for a particular duration
void playToner() {
  long elapsed_timer = 0;
  if (toner > 0) { // if this isn't a Rest beat, while the tone has 
    //  played less long than 'duration', pulse speaker HIGH and LOW
    while (elapsed_timer < durationr) {

      digitalWrite(speakerOutr,HIGH);
      delayMicroseconds(toner / 2);

      // DOWN
      digitalWrite(speakerOutr, LOW);
      delayMicroseconds(toner / 2);

      // Keep track of how long we pulsed
      elapsed_timer += (toner);
    } 
  }
  else { // Rest beat; loop times delay
    for (int j = 0; j < rest_count; j++) { // See NOTE on rest_count
      delayMicroseconds(durationr);  
    }                                
  }                                 
}

// PLAY TONE  ==============================================
// Pulse the speaker to play a tone for a particular duration
void playTone() {
  long elapsed_time = 0;
  if (tone > 0) { // if this isn't a Rest beat, while the tone has 
    //  played less long than 'duration', pulse speaker HIGH and LOW
    while (elapsed_time < duration) {

      digitalWrite(speakerOutl,HIGH);
      delayMicroseconds(tone / 2);

      // DOWN
      digitalWrite(speakerOutl, LOW);
      delayMicroseconds(tone / 2);

      // Keep track of how long we pulsed
      elapsed_time += (tone);
    } 
  }
  else { // Rest beat; loop times delay
    for (int j = 0; j < rest_count; j++) { // See NOTE on rest_count
      delayMicroseconds(duration);  
    }                                
  }                                 
}

// LET THE WILD RUMPUS BEGIN =============================
void loop() {
  // Set up a counter to pull from melody[] and beats[]
  for (int i=0; i<MAX_COUNT; i++) {
    tone = melody[i];
    beat = beats[i];

    duration = beat * tempo; // Set up timing

    playTone(); 
    // A pause between notes...
    delayMicroseconds(pause);

    if (DEBUG) { // If debugging, report loop, tone, beat, and duration
      Serial.print(i);
      Serial.print(":");
      Serial.print(beat);
      Serial.print(" ");    
      Serial.print(tone);
      Serial.print(" ");
      Serial.println(duration);
    }
  }
  
  
  // RRRRRSet up a counter to pull from melody[] and beats[]
  for (int i=0; i<MAX_COUNT; i++) {
    toner = melodyr[i];
    beatr = beatsr[i];

    durationr = beatr * tempo; // Set up timing

    playTone(); 
    // A pause between notes...
    delayMicroseconds(pause);

    if (DEBUG) { // If debugging, report loop, tone, beat, and duration
      Serial.print(i);
      Serial.print(":");
      Serial.print(beatr);
      Serial.print(" ");    
      Serial.print(toner);
      Serial.print(" ");
      Serial.println(durationr);
    }
  }
}

Don't use delay, it blocks the micro and stops it doing anything else. Take a measure from the timer and add you time to it to give you a number the timer would have reached at the expired time. then exit the loop() and on re-entry check it to see if it has expired, that is the current time is greater than the expired time. You will probably need to rewrite the program rather than trying to hack something that is fundamentally not on the right track for multiple tones.

G. Mike is quite right. The best way to architect a program that needs to apparently do several things at once is to calculate when everything needs to happen, either dynamically or up front, and then perform those tasks when their assigned times come around. I once did something similar using a strategy like this:

unsigned long t1, t2;
void setup()
{
  ...
  t1 = time the first event on left speaker should occur
  t2 = time the first event on right speaker should occur
}

void loop()
{
  unsigned long m = millis();
  if (m > t1)
  {
    bring speakerOutl high or low as appropriate
    t1 = time the next event on left speaker should occur
  }
  if (m > t2)
  {
    bring speakerOutr high or low as appropriate
    t2 = time the next event on left speaker should occur
  }
}

Make sense?

Mikal

The other option is to adopt one of the sample-based audio players and let an interrupt handle updating the output on a regular (and fast) schedule.

The interrupt will need to handle two outputs instead of one, but with port manipulation, that shouldn't be an issue.

It's a bit daunting compared to your basic bit banging audio, so I've not tried it yet, but it's next on my list for my binaural compass widget... which only plays a single frequency beep at the moment.