Arduino-based music creation system

This article is republished from :Arduino Lab  //   MAKER:JOSHIBOY61

This is a simple music creation system. It uses an Arduino to drive a passive buzzer and a row of LEDs to make the music dance. It cleverly uses an infrared remote control as the keys to record and create your own music by editing a 'sheet music' program.

The project also comes with classic pop music and movie and game soundtracks such as Shape of you, Merry Christmas, Star wars, Game of Thrones and more!

Bill of Materials


Arduino UNO R3 x 1
USB cable x 1
Patch cord x 21
Red LED x 4
Green LED x 4
Yellow LED x 2
Passive buzzer x 1
IR receiver and remote control x 1
220Ω Current Limiting Resistor x 4
Breadboard x 1

Connections

Connecting the LED and Passive Buzzer


1. Mount the LED and the buzzer on the same row of the breadboard.


2. Insert the 220Ω current limiting resistor on the left side of the LED into the GND of the breadboard.

Connecting the LEDs on both sides

1. Connect the LEDs on both sides together and install 5 resistors at the same time.

2. For easy differentiation, use the same color jumper as the LEDs.

Connecting to Arduino

1. Use five jumpers to connect the anodes of the LEDs to pins 2, 3, 4, 5, and 6.
2. Connect the GND pin of the passive buzzer to the GND of the breadboard.
3. Connect the positive pin of the passive buzzer to pin 8 of the Arduino.


4. Plug the IR receiver into the breadboard and connect the signal pin to pin 9 of the breadboard, connect its VCC pin to the 5V pin, and finally connect the GND pin to the GND of the breadboard.

Programming

Introduction to the Libraries
There are two additional libraries that will be used in the project: IRremote (for processing infrared remote signals) and toneAC (for generating tones). These libraries need to be installed in the Arduino IDE.

The source code is available for download in the project's file repository:

 
#include <IRremote.h>
#include <toneAC.h>

const int IR_RECEIVER_PIN = 8;
const int LED_PINS[] = {2, 3, 4, 5, 6, 7};
const int BUZZER_PIN = 9;

IRrecv irrecv(IR_RECEIVER_PIN);
decode_results results;

int tones[] = {262, 294, 330, 349, 392, 440, 494, 523, 587, 659, 698, 784};
int currentToneIndex = 0;

unsigned long lastCommandTime = 0;
unsigned long debounceDelay = 500;  // Set an appropriate debounce delay in milliseconds

void setup() {
  Serial.begin(9600);
  irrecv.enableIRIn();

  for (int i = 0; i < sizeof(LED_PINS) / sizeof(LED_PINS[0]); i++) {
    pinMode(LED_PINS[i], OUTPUT);
  }

  flashLEDs(2);
}

void loop() {
  if (irrecv.decode(&results)) {
    // Check for debouncing
    if (millis() - lastCommandTime > debounceDelay) {
      Serial.print("Hex Value: ");
      Serial.println(results.value, HEX);

      playTone(results.value);

      lastCommandTime = millis();  // Update the last command time
    }

    irrecv.resume();
  }

  // Flash LEDs in sequence and then in reverse
  flashLEDsSequence();
  flashLEDsReverse();
}

void playTone(unsigned long value) {
  // Map the hex values to corresponding tones
  int index = -1;
  switch (value) {
    case 0xFFA25D: index = 0; break; // CH-
    case 0xFF629D: index = 1; break; // CH
    case 0xFFE21D: index = 2; break; // CH+
    case 0xFF22DD: index = 3; break; // <<
    case 0xFF02FD: index = 4; break; // >>
    case 0xFFC23D: index = 5; break; // >||
    case 0xFFE01F: index = 6; break; // -
    case 0xFFA857: index = 7; break; // +
    case 0xFF906F: index = 8; break; // EQ
    case 0xFF9867: index = 9; break; // 100+
    case 0xFFB04F: index = 10; break; // 200+
    case 0xFF6897: index = 11; break; // 0
    case 0xFF30CF: index = 12; break; // 1
    case 0xFF18E7: index = 13; break; // 2
    case 0xFF7A85: index = 14; break; // 3
    case 0xFF10EF: index = 15; break; // 4
    case 0xFF38C7: index = 16; break; // 5
    case 0xFF5AA5: index = 17; break; // 6
    case 0xFF42BD: index = 18; break; // 7
    case 0xFF4AB5: index = 19; break; // 8
    case 0xFF52AD: index = 20; break; // 9
  }

  // Play the corresponding tone
  if (index != -1) {
    currentToneIndex = index; // Update the current tone index
    toneAC(BUZZER_PIN, tones[index], 500);
    delay(500);
    noToneAC(); // Stop the tone before playing the next one
    delay(50); // Small delay before starting the next tone
  }
}

void flashLEDs(int times) {
  for (int i = 0; i < times; i++) {
    for (int j = 0; j < sizeof(LED_PINS) / sizeof(LED_PINS[0]); j++) {
      digitalWrite(LED_PINS[j], HIGH);
      delay(100);
      digitalWrite(LED_PINS[j], LOW);
    }
    delay(500);
  }
}

void flashLEDsSequence() {
  for (int i = 0; i < sizeof(LED_PINS) / sizeof(LED_PINS[0]); i++) {
    digitalWrite(LED_PINS[i], HIGH);
    delay(100);
    digitalWrite(LED_PINS[i], LOW);
  }
}

void flashLEDsReverse() {
  for (int i = sizeof(LED_PINS) / sizeof(LED_PINS[0]) - 1; i >= 0; i--) {
    digitalWrite(LED_PINS[i], HIGH);
    delay(100);
    digitalWrite(LED_PINS[i], LOW);
  }
}

Constants and Variables
The code defines some constants and variables: 
IR_RECEIVER_PIN: Pin connected to the IR receiver.
LED_PINS: array of pins connected to the LEDs.
BUZZER_PIN: pin connected to the buzzer.
IRrecv IRrecv (IR_RECEIVER_PIN): object used to receive and decode IR signals.
decode_resultsresults: variable for storing the decoded IR signal.
tones: set of frequencies corresponding to the tones.
currentToneIndex: keep track of the currently played tone.
lastCommandTime: record the time of the last IR command to avoid fast repeating commands.
debounceDelay: delay to prevent fast triggering due to noise or repetitive signals.

Setup Function

The Setup function initializes serial communications, sets up the IR receiver, configures the LED pins as outputs, and performs an initial LED blink for visual feedback.

Loop Function

The loop function continuously checks the incoming IR signal. If a signal is received, a sufficiently long de-jittering time elapses, then the hexadecimal value of the signal is printed, the corresponding musical note is played, and the last command time is updated. In addition, it triggers the function to flash the LEDs in sequence and in reverse.

playTone function

The playTone function maps a specific IR remote hexadecimal value to the corresponding musical tone. When a valid value is found, it plays the associated tone via a buzzer. After a short pause, it moves to the next tone. If you want to play a song, you can search the Arduino related websites and you will find some nice music such as Happy Birthday song and Super Mario theme song.

Blinking LED Functions

There are three blinking LED functions:
1、fashLEDs:Pressing the mode blinks the LEDs to indicate the start of the instruction code.
2、flashLEDsSequence:Blinking LEDs in sequence.
3、flashLEDsReverse:Blinks the LEDs in the opposite direction.

Play Song


Now you can start playing a song. You have mastered the notes, so feel free to experiment with the sounds and tones in the code. You can also add your favorite songs to the code.