Go Down

Topic: Stereo Arduino (Help) (Read 450 times) previous topic - next topic

Dragonos


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

Code: [Select]

// 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);
   }
 }
}


Grumpy_Mike

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.

mikalhart

#2
Sep 17, 2008, 07:13 pm Last Edit: Sep 17, 2008, 08:30 pm by mikalhart Reason: 1
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:

Code: [Select]
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


Syvwlch

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.
----------
Mathieu

Go Up