Introduction: Color Detecting Sound Player

This is my first Arduino project, made as part of a school project using the Arduino Yún. The Color Detecting Sound Player will, as the name suggests, detect colors and adjust a tune based on the color that's held in front of the scanner. The project consists of two parts: the scanner that will detect the colors, and the speaker that will play the sounds.

Step 1: What You Will Need

What you will need:

  • An Arduino (I'll be using an Arduino Yún).
  • Three LED-lights (one red, one green and one blue).
  • An LDR Light Scanner.A 220 ohm resistor.
  • A Piëzo Speaker.
  • Wires.

Optional:

  • Another LED-light.
  • Momentary button or Switch.
  • 10K ohm resistor.
  • Another 220 ohm resistor.

The optional part is for a little on-off button (to safe your sanity while working on the endlessly bleeping speaker), and a little light that will blink when the scanner is ready.

Step 2: Building the Scanner

The scanner will work by reflecting light off of a surface. Colours absorb certain colours and reflect others. By shining a red, green and blue LED on to the surface one by one, we can measure how much light is reflected each time. Doing so will allow us to get the red, green, blue (RGB) values that make up the colour of the surface.

Building the scanner isn't too complicated, and can be done as is shown in the schematic.

Make sure the scanner is fully sealed off except for one opening. Additionally there should be a barrier between the LED-lights and the LDR sensor. All this is to make sure that only light reflected from the surface of the object you're trying to scan reaches the sensor. This seal should preferably be black and dull for the best performance.

Step 3: Building the Rest

The rest of the construction consists of three parts. Each of these parts works on its own, can work individually, and can be connected directly to the arduino. The three parts consist of the Speaker, an additional LED and a toggle button.
The Speaker is what will eventually be playing the tones, and is attatched directly to the arduino.
The LED light that will give some feedback when setting up the scanner; it will blink three times to indicate that the first white and black surface scans are completed.
Lastly the toggle button is a little button that can be used to turn the speaker on and off.

As mentioned before all of these parts are fairly straightforward, and building the circuit as is done in the added schematic should work just fine.

Step 4: The Code


Now that all the building is done, we can start on the code.

#include "pitches.h"

// notes in the melody: int melody[] = {
NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};

// note durations: 4 = quarter note, 8 = eighth note, etc.: int noteDurations[] = { 4, 8, 8, 4, 4, 4, 4, 4
};

int LED_ARRAY[] {2, 3, 4}; int LED_RED = 2; int LED_GREEN = 3; int LED_BLUE = 4;

int TOGGLEBUTTON = 6; int FEEDBACK_LED = 8; int SPEAKER = 10;

float colourArray[] = {0,0,0}; float whiteArray[] = {0,0,0}; float blackArray[] = {0,0,0};

bool toggleSwitch = true; bool lastState = false;

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

pinMode (SPEAKER, OUTPUT); pinMode (TOGGLEBUTTON, INPUT); pinMode (FEEDBACK_LED, OUTPUT);

pinMode (LED_RED, OUTPUT);
pinMode (LED_GREEN, OUTPUT);
pinMode (LED_BLUE, OUTPUT);

SetBalance (); }

This is the initial setup of the code. First we have the melody containing the notes that are going to be played, followed by the duration of those notes. These two things combined form the melody that's going to be played. Following that are all the pin variables as well as a couple of variables that will be used later on.
In the Setup() function we set the pinmodes and start the initialization of the scanner by calling the SetBalance() function.

void SetBalance () {
ReadyCheck (); delay (5000); //Setting values for white for (int i = 0; i < 3; i++) { digitalWrite (LED_ARRAY[i], HIGH); delay (100); whiteArray [i] = analogRead (A0); digitalWrite (LED_ARRAY[i], LOW); } PrintRGB (whiteArray); ReadyCheck (); delay (5000); //Setting values for black for (int i = 0; i < 3; i++) { digitalWrite (LED_ARRAY[i], HIGH); delay (100); blackArray [i] = analogRead (A0); digitalWrite (LED_ARRAY[i], LOW); } PrintRGB (blackArray); ReadyCheck (); }
void ReadyCheck () {

for (int n = 0; n < 3; n++) { for (int i = 0; i < 3; i++) { digitalWrite (LED_ARRAY[i], HIGH); digitalWrite (FEEDBACK_LED, HIGH); } delay (300); for (int i = 0; i < 3; i++) { digitalWrite (LED_ARRAY[i], LOW); digitalWrite (FEEDBACK_LED, LOW); } delay (300); } }

The SetBalance() function will open with a 5 second delay so that you have time to hold a white sample in front of the scanner. It will scan the sample by turning on each of the three coloured LEDs at a time, and then reading how much light is reflected onto the sensor. Once it's done scanning another 5 second delay will be held so you have time to replace the white sample with a black sample which it will once again scan. Doing this will give you a maximum and minimum value (black and white) which will be used to normalize future colour scans.
After each of these scans the ReadyCheck() function will be called. All this function does is flash the scanner and the feedback LED (the one outside of the scanner itself) three times to signal you that the scan is done.

void loop () {
int n = sizeof(melody)/sizeof(melody[0]); for (int thisNote = 0; thisNote < n; thisNote++) { //Serial.println (toggleSwitch); if (ToggleCheck ()) { SetColour (); PlayNote (thisNote); } } }

This is the loop() function. For each note in the melody it will first call to scan for the current colour using the SetColour() function. Once this is completed the PlayNote() function will be called, which will then play the actual note and adjust it to the colour scanned before.

void SetColour () {  for (int i = 0; i < 3; i++) {
    digitalWrite (LED_ARRAY[i], HIGH);
    delay (50);
    colourArray [i] = analogRead (A0);
    digitalWrite (LED_ARRAY[i], LOW);
    float greyDiff = whiteArray[i] - blackArray[i];
    colourArray[i] = ((colourArray[i] - blackArray[i]) / greyDiff) * 255;
    delay (50);
  }
}

This is the SetColour() function that will scan for the colour currently being held infront of the scanner. Much like the SetBalance() function earlier, it does this by lighting up each LED one by one, and measuring the reflected light each time. Once he has scanned for a value it will normalize this using the minimum and maximum values (the black and white values we setup in the SetBalance() function

void PlayNote (int note) {  int speedInput = (colourArray[0] <= 0) ? 1 : colourArray[0];
  speedInput = (speedInput / 2) - 64;
  int toneInput = (colourArray[2] <= 0) ? 1 : colourArray[2];
  toneInput = (toneInput - 128) * 1.5;  int noteDuration = speedInput + (1000 / noteDurations[note]);
  noteDuration = (noteDuration <= 0) ? 1 : noteDuration;
  int playTone = melody[note] + toneInput;
  playTone = (playTone <=0 ) ? 1 : playTone;
  
  tone(SPEAKER, playTone, noteDuration);
  
  int pauseBetweenNotes = noteDuration * 1.30;
  delay(pauseBetweenNotes);
  noTone(SPEAKER);
}

This is the PlayNote() function. It first calculates the speed and pitch at which the melody should be played. It adjusts the speed based on the amount of red that was scanned, and the pitch based on the amount of blue that was scanned. The green would be used for volume, but the Piëzo speaker doesn't have that option. Once it's done with these calculations it will play the tone

bool ToggleCheck () {    bool currentState = digitalRead (TOGGLEBUTTON);
    Serial.println (digitalRead (TOGGLEBUTTON));
    if (currentState == true && lastState == false) {
      toggleSwitch = !toggleSwitch;
    }
    lastState = currentState;    return toggleSwitch;
}

And last but by no means least it's the savior of sanity; protector of ears; and defender of mankind: the togglebutton. This is a small function that simply swaps a boolean between true and false whenever the button is pressed. The loop() function will only play a tone when this boolean is true.

And that's all for the code.

Step 5: All Finished

Too easy?
- Allow it to be able to play from a selection of multiple tunes.
- Try adjusting the project to play single tones based on colours; allowing you to make up melodies on the spot using an array of colours.
- Make it able to to play and adjust mp3 files instead of just tones.

That's all for this project. You are now able to adjust a simple melodie using colour. Hope you enjoyed it, and...

bleeeep bleep bleep bleep bleep bleep bleeeep bleeeep bleep bleeeep bleep bleeeep bleep bleep bleep /
bleep bleep bleeeep bleep bleeeep bleeeep bleeeep bleep bleeeep bleep /
bleep bleeeep bleep bleep bleep bleeeep bleeeep bleep bleep bleep bleep bleeeep bleep bleeeep bleeeep bleep.