1

I'm trying to replicate a short music clip with two piezos, and I want them to play at the same time. While the right piezo is playing, I want the left one to still be looping. The problem is, I'm not sure how.

enter image description here

//Left hand
const int leftPin = 10; /Left pin
const int leftTones[] = {123.4, 103.83, 138.59, 92.50}; //The looping left tones
const int leftDelays[] = {700, 1300, 900, 900}; //How long those tones last
const int leftNotes = 4; //How many left notes there are
//Right hand
const int rightPin = 2; //Right pin
const int rightTones[] = {739.99, 587.33, 587.33, 659.25, 698.46, //The looping right tones
659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 493.88, 
554.37, 587.33, 659.25, 587.33, 554.37, 880.00, 783.99, 739.99, 
587.33, 587.33, 659.25, 698.46, 659.25, 587.33, 554.37, 587.33, 
659.25, 739.99, 987.77, 987.77, 1108.73, 1174.66, 783.99, 739.99, 
698.46, 1174.66, 1318.51};
const int rightDelays[] = {700, 1000, 100, 100, 300, 300, 200, //How long those tones last
300, 300, 200, 700, 700, 250, 150, 200, 400, 300, 300, 400, 200,
700, 1000, 100, 100, 300, 300, 200, 400, 300, 200, 700, 700, 300,
200, 400, 300, 200, 400, 300, 200};
const int rightNotes = 40; //How many right notes there are
void setup(){
 pinMode(leftPin, OUTPUT);
 pinMode(rightPin, OUTPUT);
 delay(1000);
}
void loop(){
 for (int i = 0; i < leftNotes; i++){
 tone(leftPin, leftTones[i]);
 delay(leftDelays[i]);
 noTone(leftPin);
 }
 for (int i = 0; i < rightNotes; i++){
 tone(rightPin, rightTones[i]);
 delay(rightDelays[i]);
 noTone(rightPin);
 }
}

With this code, the left piezo plays first, and then the right piezo plays. It should be at the same time.

Edited Code:

long currentMillis = 0;
long leftPreviousMillis = 0; // previous time for left hand
long rightPreviousMillis = 0; // previous time for right hand
const int leftNotes = 4; // The amount of left notes
const int rightNotes = 40; // The amount of right notes
int leftIndex = 0; // The specific index for the left piezo
int rightIndex = 0; // The specific index for the right piezo
const int leftPin = 10; // The left piezo
const int rightPin = 2; // The right piezo
// The specific left pitches (as float)
const float leftTones[] = {123.4, 103.83, 138.59, 92.50};
// How long the left pitches last for
const long leftDelays[] = {700, 1300, 900, 900};
// The specific right pitches (as float)
const float rightTones[] = {739.99, 587.33, 587.33, 659.25, 698.46, 659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 493.88, 554.37, 587.33, 659.25, 587.33, 554.37, 880.00, 783.99, 739.99, 587.33, 587.33, 659.25, 698.46, 659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 987.77, 1108.73, 1174.66, 783.99, 739.99, 698.46, 1174.66, 1318.51};
// How long the right pitches last for
const long rightDelays[] = {700, 1000, 100, 100, 300, 300, 200, 300, 300, 200, 700, 700, 250, 150, 200, 400, 300, 300, 400, 200, 700, 1000, 100, 100, 300, 300, 200, 400, 300, 200, 700, 700, 300, 200, 400, 300, 200, 400, 300, 200};
void setup() {
 pinMode(leftPin, OUTPUT);
 pinMode(rightPin, OUTPUT);
 Serial.begin(9600);
 delay(1000);
 tone(rightPin, rightTones[rightIndex]);
 tone(leftPin, leftTones[leftIndex]);
}
void loop() {
 currentMillis = millis();
 // Left hand notes
 if (currentMillis - leftPreviousMillis >= leftDelays[leftIndex]) {
 noTone(leftPin); // Turn off the left note
 leftPreviousMillis = currentMillis;
 leftIndex++;
 if (leftIndex == leftNotes) // Reset left hand index
 leftIndex = 0;
 tone(leftPin, leftTones[leftIndex]); // Turn on the new left note
 }
 // Right hand notes
 if (currentMillis - rightPreviousMillis >= rightDelays[rightIndex]) {
 noTone(rightPin); // Turn off the right note
 rightPreviousMillis = currentMillis;
 rightIndex++;
 if (rightIndex == rightNotes) // Reset right hand index
 rightIndex = 0;
 tone(rightPin, rightTones[rightIndex]); // Turn on the new right note
 }
}

I've done some testing, and I think it's a problem with the tones function. Right now, this code only plays the right hand notes. The problem is this part:

tone(rightPin, rightTones[rightIndex]);
tone(leftPin, leftTones[leftIndex]);

When I do this:

tone(leftPin, leftTones[leftIndex]);
tone(rightPin, rightTones[rightIndex]);

Only the left hand notes are heard. But, it's not perfect. There's little beeps and buzzes every now and then. This leaves me with the conclusion that if there are two tones at the same time, it only plays the one it reads first. I've tested it with simpler code, and it stands true.

So that begs the question, is it even possible to use two piezos at the same time with one Arduino? I'm testing it with the Arduino simulator tinkercad, so maybe that's the problem? My code works for the left piezo, and the right piezo. But when you put them together, everything messes up.

asked Nov 4, 2023 at 13:13
4
  • Google "non blocking code" and "timing without delay". This topic is one of the single most discussed issues about programming. You'll find that thousands before you have had this problem. The solution is well documented. Commented Nov 4, 2023 at 13:58
  • I've completely overwritten my previous code in my edited version right above, but I think may be a problem with the tones function itself. My reasoning is above. Commented Nov 4, 2023 at 20:08
  • Please don't change your question after you have an answer. Commented Nov 4, 2023 at 20:31
  • Tone can only be used on one pin at a time. Tone uses unsigned int for it's "frequency" parameter, not floating point numbers. This library claims it can play 2 different ones on 2 different pins: github.com/nathanRamaNoodles/Noodle-Synth Commented Nov 4, 2023 at 20:31

2 Answers 2

0

It's always good to look at the documentation when you have a question about how a piece of code works. In this case I looked at the page for the tone function which can be found here. https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/

And the second sentence on that page says it all:

Only one tone can be generated at a time. If a tone is already playing on a different pin, the call to tone() will have no effect. If the tone is playing on the same pin, the call will set its frequency.

answered Nov 4, 2023 at 20:30
1
  • Ah, you where faster than me. Also: The Polytone seems promising as alternative. Commented Nov 4, 2023 at 20:43
0

How do you use two piezos at the same time?

Consider using a finite state machine type of programming method.

As has been discovered, using calls to the delay() function (where the processor does nothing) blocks any other feature of the sketch (user's program). In a finite state machine programming pattern, there are no calls to the delay() function. Instead the sketch's loop() function is allowed to execute as fast as possible. The trick is to control what code is executed in the loop() function based on a state machine. And, in this case, use time to change between different states.

In an Arduino platform (the hardware and software you never or seldom see that makes up an Arduino) a counter is always tracking elapsed time. Use the millis() function to retrieve the current value in milliseconds (1000 milliseconds = 1 second) each time through the loop() function. Consider using a 2 state state machine. In the 1st state get the current counter value, add to it the delay in milliseconds of the next note, start the note playing and finally change the variable tracking states to the 2nd state. The next time through the loop() function, while in the 2nd state, check if the response from calling millis() again is larger then the value saved while in the 1st state. If it is, stop playing the note and change the variable tracking states to the 1st state.

Once working, create a second similar state machine to play the counter melody.

However, as delta-g has pointed out, the library picked out by the O.P. apparently can not play more than one note at a time. But,ve7jro has pointed out that this Arduino tunes library may be able to satisfy the requirement of playing 2 notes at the same time as stated in the O.P.'s question.

Creating a state machine in a invaluable programming lesson. However, this Arduino state machine library is available should the programmer wish to take advantage of it.

answered Nov 4, 2023 at 14:45
2
  • I've put my newest code at the bottom of my previous response. Commented Nov 4, 2023 at 18:28
  • @Harrisino, you have accepted an answer. So don't edit your question into a different one. Only edit it to make it better. If you have a different question, start over by asking a new question. The point of stackexchange is to accumulate questions & answers for people to search through who have similar questions. Think how confusing the altered question will be to those people. BTW, you accepted an answer that says you can not do what your question asked for. I still think a state machine is what you want. And perhaps a better tunes library. Commented Nov 4, 2023 at 23:22

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.