Arduino based piano with recording and playback function

Original text: https://circuitdigest.com/microcontroller-projects/arduino-piano-with-record-and-playback

Arduino based piano with recording and playback function

ARDUINO project

Pass by** Aswinth Raj **June 12, 2018

Arduino for those who don't have a background in electronics, building things easily is a blessing. It used to be a great prototyping tool, or try something great. In this project, we will use Arduino to build a small and interesting piano. This piano has only eight buttons and buzzer, which is very common. It uses Arduino's * tone() * function to create various types of piano notes on the speaker. In order to add some fun to it, we have added recording function to the project, which enables us to play music and record it, and repeat it when necessary. Sounds interesting! So let's start building.

Materials required:

  • Arduino Uno
  • 16 * 2 LCD display
  • Buzzer
  • Fine tuning 10k
  • SPDT Switch
  • Buttons (8)
  • Resistor (10k, 560R, 1.5k, 2.6k, 3.9, 5.6k, 6.8k, 8.2k, 10k)
  • Bread board
  • Connecting line

Circuit diagram:

The complete Arduino piano project can be built on a bread board with some connecting wires. The following figure shows the circuit diagram made with fritzing, which shows the test board view of the project

Just follow the circuit diagram and connect the wires accordingly, and the button and buzzer used with the PCB module can be used. However, in the actual hardware, we only use the switch and buzzer, which will not cause you too much trouble because they have the same pin type. You can also refer to the following hardware image for connection.

The resistance values from the left are arranged in the following order: 10k, 560R, 1.5k, 2.6k, 3.9, 5.6k, 6.8k, 8.2k and 10k. If the same DPST switch is not available, an ordinary toggle switch can be used, as shown in the circuit diagram above. Let's take a look at the following schematic diagram to see why we have established the connection.

Schematic diagram and Description:

The schematic diagram of the circuit diagram shown above is given below, which is also made by Fritzing.

One of the main connections we must understand is how to connect eight buttons to Arduino through the analog A0 pin. Basically, we need 8 input pins, which can be connected to 8 input buttons, but for such projects, we can't only use the 8 pins of the microcontroller for buttons, because we may need them in the future. In our example, we have To connect of LCD display.

Therefore, we use the analog pin of Arduino and form a variable resistance Voltage divider To complete the circuit. In this way, when each button is pressed, a different analog voltage will be supplied to the analog pin. An example circuit showing only two resistors and two buttons is shown below.

In this case, when the button is not pressed, the ADC pin will receive + 5V voltage; If the first button is pressed, the voltage divider is completed through 560R resistor; If the second button is pressed, the voltage divider will use 1.5 competition. k resistance. In this way, the voltage received by the ADC pin will change according to the formula of the voltage divider. If you want to know more about the working principle of the voltage divider and how to calculate the voltage value received by the ADC pin, you can use this function Voltage divider calculator Page.

In addition, all connections are straightforward. The LCD is connected to pins 8, 9, 10, 11 and 12. The buzzer is connected to pin 7 and the SPDT Switch is connected to pin 6 of Arduino. The whole project is powered by the USB port of the laptop. You can also connect the Arduino to a 9V or 12V power supply through the DC jack, and the project will still operate normally.

Learn about Arduino's * Tone() * function:

Arduino has a convenient tone () function, which can be used to generate varying frequency signals, which can be used to generate different sounds through the buzzer. So let's see how this function works and how it works with Arduino.

Before that, we should know the working principle of piezoelectric buzzer. We may have learned in school that piezoelectric crystals are nothing more than crystals that convert mechanical vibration into electrical energy, and vice versa. Here, when we apply a variable current (frequency), the crystal will vibrate and produce sound. Therefore, in order to make the piezoelectric buzzer produce some noise, we must make the piezoelectric crystal vibrate. The tone and tone of the noise depend on the speed of the crystal vibration. Therefore, the tone and pitch can be controlled by changing the frequency of the current.

OK, how do we get the variable frequency from Arduino? This is using tone()function A place to live. Tone() can generate a specific frequency on a specific pin. If necessary, the duration can also be mentioned. The syntax of tone() is

Syntax  //syntax
tone(pin, frequency)
tone(pin, frequency, duration)

Parameters
pin: the pin on which to generate the tone
frequency: the frequency of the tone in hertz – unsigned int
duration: the duration of the tone in milliseconds (optional1) – unsigned long

The value of the pin can be any digital pin. I used pin 8 here. The frequency that can be generated depends on the size of the timer in the Arduino development board. For UNO and most other common boards, the minimum frequency that can be generated is 31Hz and the maximum frequency that can be generated is 65535Hz. However, we humans can only hear frequencies between 2000 Hz and 5000 Hz.

Play piano on Arduino:

OK, before I start this topic, please make it clear that I am a novice in notes or piano, so if anything mentioned under this title is annoying, please forgive me.

Now we know that the tone function can be used in Arduino to produce some sounds, but how to use the same tone to play the tone of a specific note. Fortunately for us, there is a library called "pitches.h" written by Brett Hagman * *** The library contains all information about which frequency is equal to which note on the piano. I'm surprised that this library can actually work well and play every note on the piano. I use it to play piano notes of Pirates of the Caribbean, crazy frogs, Mario and even Titanic. They sound great. too bad! We have no topic here, so if you are interested, you can Using Arduino project Play melody . You will also find information about pitches H for more information. Libraries in this project.

Our project has only 8 buttons, so each button can only play a specific note, so we can only play 8 notes in total. I chose the most commonly used notes on the piano, but you can choose any 8 notes, or even expand the project and add more notes with more buttons.

The notes selected in this project are C4, D4, E4, F4, G4, A4, B4 and C5, which can be played using buttons 1 to 8 respectively.

Programming Arduino:

With enough theoretical knowledge, let's start the interesting part of Arduino programming. The full Arduino plan is given at the end of this page. If you desire, you can jump down or read further to learn how the code works.

In our Arduino program, we must read the analog voltage from pin A0, then predict which button is pressed and play the corresponding tone of the button. When doing this, we should also record which button the user pressed and how long he / she pressed it, so that we can recreate the tone played by the user later.

Before proceeding to the logical part, we must state the eight notes to be played. Then from the tone Obtain the corresponding frequency of notes in the h library, and then form an array, as shown below. Here, the frequency of playing note C4 is 262, and so on.

int notes [] = {262,294,330,349,392,440,494,523}; //Set C4, D4, E4, F4, G4, A4, B4,

Next, we must mention which pin the LCD display is connected to. If you follow the exact same schematic diagram given above, you do not need to make any changes here.

const int rs = 8, en = 9, d4 = 10, d5 = 11, d6 = 12, d7 = 13; //Pins to which LCD is connected
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

Next, in the setting function, we only initialize the LCD module and serial monitor for debugging. We will also display introductory messages to ensure that everything goes as planned. Next * *, in the * main * loop function, we have two while loops * *.

As long as the * * SPDT Switch is placed in more recording positions, * * will perform a cycle for a while. In recording mode, the user can pay for the required tone and save the tone being played at the same time. So the while loop is as follows

  while(digitalRead(6)== 0)//If the toggle switch is set to recording mode
  {
    lcd.setCursor(0,0); lcd.print(" Recording ..");
    lcd.setCursor(0,1);
    Detect_button();
    Play_tone();
  }

You may have noticed * * that there are two functions * * in the while loop. First function * * * Detect_button() * is used to find which button the user pressed. The second function is * Play_tone() * * * used to play the corresponding tone. In addition to this function, * detect_ The button () function also records which button was pressed, while play_ The tone() * function records the time the button was pressed.

*** detect_ Inside the button() * function, * * we read the analog voltage from pin A0 and compare it with some predefined values to find out which button was pressed. This value can be determined by checking the analog value read by each button using the voltage divider calculator above or using a serial monitor.

void Detect_button()
{
  analogVal = analogRead(A0); //read the analog voltag on pin A0
  pev_button = button; //remember the previous button pressed by the user

  if (analogVal < 550)
    button = 8;

  if (analogVal < 500)
    button = 7;

  if (analogVal < 450)
    button = 6;

  if (analogVal < 400)
    button = 5;

  if (analogVal < 300)
    button = 4;

  if (analogVal < 250)
    button = 3;

  if (analogVal < 150)
    button = 2;

  if (analogVal < 100)
    button = 1;

  if (analogVal > 1000)
    button = 0;
   
/****Rcord the pressed buttons in a array***/
  if (button != pev_button && pev_button != 0)
  {
    recorded_button[button_index] = pev_button;
    button_index++;
    recorded_button[button_index] = 0;
    button_index++;
  }
/**End of Recording program**/
} 

As mentioned earlier, in this function, we also record the sequence of pressing buttons. The recorded value is stored in a file named * recorded_ In the array of button []* We first check whether a new button is pressed. If it is pressed, we will also check whether it is not button 0. Button 0 is nothing, but no button is pressed. In the if loop, we store the value in the variable button_index the given index location, and then increase the index value to avoid over writing at the same location.

/****Rcord the pressed buttons in a array***/
  if (button != pev_button && pev_button != 0)
  {
    recorded_button[button_index] = pev_button;
    button_index++;
    recorded_button[button_index] = 0;
    button_index++;
  }
/**End of Recording program**/

**On * play_ Inside the tone() * function, * * we will play the corresponding sound for the pressed button by using multiple if conditions. Similarly, we will use a file called * recorded_ An array of time [], in which the duration of the button being pressed is saved. This operation is similar to recording a sequence of buttons by using the millis() * function to determine when each button is pressed. In addition, to reduce the size of the variable, we divide the value by 10. For button 0, this means that the user doesn't press anything, and we don't sound a tone for the same time. The complete code inside the function is shown below.

void Play_tone()
{

 /****Rcord the time delay between each button press in a array***/

  if (button != pev_button)
  {
    lcd.clear(); //Then clean it
    note_time = (millis() - start_time) / 10;
    recorded_time[time_index] = note_time;
    time_index++;
    start_time = millis();
  }
  /**End of Recording program**/

  if (button == 0)
  {
    noTone(7);
    lcd.print("0 -> Pause..");
  }

  if (button == 1)
  {
    tone(7, notes[0]);
    lcd.print("1 -> NOTE_C4");
  }

  if (button == 2)
  {
    tone(7, notes[1]);
    lcd.print("2 -> NOTE_D4");
  }

  if (button == 3)
  {
    tone(7, notes[2]);
    lcd.print("3 -> NOTE_E4");
  }

  if (button == 4)
  {
    tone(7, notes[3]);
    lcd.print("4 -> NOTE_F4");
  }

  if (button == 5)
  {
    tone(7, notes[4]);
    lcd.print("5 -> NOTE_G4");
  }

  if (button == 6)
  {
    tone(7, notes[5]);
    lcd.print("6 -> NOTE_A4");
  }

  if (button == 7)
  {
    tone(7, notes[6]);
    lcd.print("7 -> NOTE_B4");
  }

  if (button == 8)
  {
    tone(7, notes[7]);
    lcd.print("8 -> NOTE_C5");
  }
}

Finally, after recording, the user must switch the DPST to another direction to play the recorded tone. After this operation, the program will jump out of the previous while loop and enter the second while loop. In this loop, we play notes in the order of buttons for the duration of the previously recorded time. The code to do this is shown below.

  while (digitalRead(6) == 1) //If the toggle switch is set in Playing mode
  {
  lcd.clear();
  lcd.setCursor(0, 0);  lcd.print("Now Playing..");

  for (int i = 0; i < sizeof(recorded_button) / 2; i++)
  {
    delay((recorded_time[i]) * 10); //Wait for before paying next tune

    if (recorded_button[i] == 0)
      noTone(7); //user dint touch any button
    else
      tone(7, notes[(recorded_button[i] - 1)]); //play the sound corresponding to the button touched by the user
  }
  }
}

Play, record, replay and repeat!:

Make the hardware according to the circuit diagram shown, and then upload the code to the Arduino board and its display time. Put the SPDT into Recording mode and start playing the tone you selected. Pressing each button will produce a different tone. In this mode, the LCD will display "Recording...". In the second line, you will see the name of the currently pressed note, as shown below

After playing the tone, turn the SPDT Switch to the other side, the LCD should display "Now Play...", and then start playing the tone just played. As long as the toggle switch is held in the position shown in the figure below, the same tone will be played again and again.

The complete work of the project can be found in the following video. I hope you understand the project and enjoy building it. If you have any problems building this document, please post them in the comments section or use the forum for technical assistance on your project. Also, don't forget to check out the demo video below.

code

/*
   Arduino based Piano and Record and play option
   Code by: B. Aswinth Raj
   Website: www.circuitdigest.com
   Dated: 22-05-2017
*/

#include <LiquidCrystal.h>

int notes[] = {262, 294, 330, 349, 392, 440, 494, 523}; // Set frequency for C4, D4, E4, F4, G4, A4, B4, C5

const int rs = 8, en = 9, d4 = 10, d5 = 11, d6 = 12, d7 = 13; //Pins to which LCD is connected
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

char button = 0;
int analogVal;
char REC = 0;

int recorded_button[200];
int pev_button;

int recorded_time [200];
char time_index;

char button_index = 0;

unsigned long start_time;
int note_time;

void setup() {

  Serial.begin(9600);
  pinMode (6, INPUT);

  lcd.begin(16, 2); //We are using a 16*2 LCD display
  lcd.print("Arduino Piano"); //Display a intro message
  lcd.setCursor(0, 1);   // set the cursor to column 0, line 1
  lcd.print("-CircuitDigest"); //Display a intro message

  delay(2000); //Wait for display to show info
  lcd.clear(); //Then clean it

}

void loop() 
{

  while (digitalRead(6) == 0) //If the toggle switch is set in recording mode
  {
    lcd.setCursor(0, 0); lcd.print("Recording..");
    lcd.setCursor(0, 1);

    Detect_button();
    Play_tone();
  }

 
  while (digitalRead(6) == 1) //If the toggle switch is set in Playing mode
  {
  lcd.clear();
  lcd.setCursor(0, 0);  lcd.print("Now Playing..");

  for (int i = 0; i < sizeof(recorded_button) / 2; i++)
  {
    delay((recorded_time[i]) * 10); //Wait for before paying next tune

    if (recorded_button[i] == 0)
      noTone(7); //user dint touch any button
    else
      tone(7, notes[(recorded_button[i] - 1)]); //play the sound corresponding to the button touched by the user
  }
  }
}

void Detect_button()
{
  analogVal = analogRead(A0); //read the analog voltag on pin A0

  pev_button = button; //remember the previous button pressed by the user

  if (analogVal < 550)
    button = 8;

  if (analogVal < 500)
    button = 7;

  if (analogVal < 450)
    button = 6;

  if (analogVal < 400)
    button = 5;

  if (analogVal < 300)
    button = 4;

  if (analogVal < 250)
    button = 3;

  if (analogVal < 150)
    button = 2;

  if (analogVal < 100)
    button = 1;

  if (analogVal > 1000)
    button = 0;

    
/****Rcord the pressed buttons in a array***/
  if (button != pev_button && pev_button != 0)
  {
    recorded_button[button_index] = pev_button; 
    button_index++;
    recorded_button[button_index] = 0;
    button_index++;
  }
/**End of Recording program**/
}

void Play_tone()
{

 /****Rcord the time delay between each button press in a array***/
  if (button != pev_button)
  {
    lcd.clear(); //Then clean it
    note_time = (millis() - start_time) / 10;

    recorded_time[time_index] = note_time;
    time_index++;

    start_time = millis();
  }
  /**End of Recording program**/

  if (button == 0)
  {
    noTone(7);
    lcd.print("0 -> Pause..");
  }

  if (button == 1)
  {
    tone(7, notes[0]);
    lcd.print("1 -> NOTE_C4");
  }

  if (button == 2)
  {
    tone(7, notes[1]);
    lcd.print("2 -> NOTE_D4");
  }

  if (button == 3)
  {
    tone(7, notes[2]);
    lcd.print("3 -> NOTE_E4");
  }

  if (button == 4)
  {
    tone(7, notes[3]);
    lcd.print("4 -> NOTE_F4");
  }

  if (button == 5)
  {
    tone(7, notes[4]);
    lcd.print("5 -> NOTE_G4");
  }

  if (button == 6)
  {
    tone(7, notes[5]);
    lcd.print("6 -> NOTE_A4");
  }

  if (button == 7)
  {
    tone(7, notes[6]);
    lcd.print("7 -> NOTE_B4");
  }

  if (button == 8)
  {
    tone(7, notes[7]);
    lcd.print("8 -> NOTE_C5");
  }
}

Added by richrock on Sat, 19 Feb 2022 03:09:45 +0200