$USD
  • EUR€
  • £GBP
  • $USD
TUTORIALS Arduino

Musical Fountain Project

DFRobot May 28 2013 341

In this month, I finally finished my musical fountain project. To be honest, it is quite a big challenge for me to complete the whole project. I think this project is interesting and thus I would like to share my experience with you. There are two main stages in this project. The first one is to design a simple musical box through processing and therefore the music box is able to send music signals to the Arduino board. The second step is to connect two pumps to the Arduino board and enabling the pumps to change water flow according to the music signal sent from processing.
Here's a video demo of how it works.

 

Hardware Congifuration

  1. Two DC 6V~24V Water Pumps
      Detail information for the pump:
  • Input: DC 6V~24V 2~50W
  • Hmax: 80~600cm
  • Qmax: 450~1200L/H

    ( Caution: The two pumps are intended for use with water only)
  1. An Arduino Romeo V2.0 board
  1. A DC Power Supply
  1. Four Capacitances
  • Two 25V-1000μF capacitances;
  • Two 50V-4.7μF capacitances;
  1. Six Light Disc with 7 SMD RGB LEDs
Processing Part

Libraries needed:
1) ControlP5: http://www.sojamo.de/libraries/controlP5/
2) Minim: http://code.compartmental.net/tools/minim/quickstart/
3) Serial
*How to add a new library to Processing’s libraries:
Processing’s libraries are usually saved in 
C:UsersUserNameMy DocumentsProcessing libraries
  So, you can add your new library into the “libraries” folder.
*How to make a simple musical box
1. Functions of the musical box
a) Two Boxes to show Serial Port and Serial Baud Rate separately
b) A Box to select a song from a Music List
The music box can play the songs in the music list one by one automatically.
c) Display the information of a song which is playing
d) Present the Fast Fourier Transform of the music signal (Average Spectrum) 
e) A Countdown Timer to show how much time is left of a song
f) A Volume Controller
g) A Play/Stop icon to control whether send music signal to Arduino

 

2. How to realize the seven functions of the music box
a) Serial Number box and Serial Baud Rate box
     Variable declaration:
       JComboBox BaudBox;
       JComboBox PortBox
       JComboBox mp3Box;
       Serial ArduinoPort;
    Set the size of the boxes in Setup ():
       MusicBox(370, 60);
       DetectDevices(450, 20);
       BaudComboBox(450, 40); 
    Functions:

??// Setting for the Serial Baud Rate Box
??private void BaudComboBox(int x, int y)
??{
??     ……
??}
??
????// Setting for the Serial Port Box
??// If an Arduino board is communicating with Processing, the Serial Port Box will detect the Serial Port 
???// automatically in this function.
???private void DetectDevices(int x, int y)
??{
??    …… 
}

     b) Music Box
         Variable declaration:
       JComboBox mp3Box;
        String PlayingFileName;
        String PlayingFileName;
        Minim minim;
        AudioPlayer Player;
        Setup ():

??MusicBox(370, 60);   // Set the size of the music box in Setup ()
??????
??????loadFilenames();    // Load the names of the songs in the music list    
??
??// Freshing action to make the music box play songs in the music list one by one;
????//Also, if the last song in the music list is finished, the music box 
???//will start to play from the first song again
freshMusic(); 

Functions:
Part 1:  Music Box

?????// Setting for the Music Box
??public void MusicBox(int x, int y)
??{
??    ……
??????}

Part 2:  Set the playing mode of the songs in the music list

The music box can play the songs in the music list one by one automatically.
If the last song in the music list is finished, the music box will start to play from the first song again.

???// Freshing action to make the music box play songs in the music list one by one
???void freshMusic() 
???{
??     ……
???}
???// Load the names of the songs in the music list
???void loadFilenames() 
???{
??     ……
???}
???
???/** This class implements the FilenameFilter interface.
??? *  The Accept method returns true for .java, .class and .jar files.
?????? */
??????class OnlyJava implements FilenameFilter 
???{
???   …… 
???}
???
???//The ActionListener can make the music box play the song you select from the list
???public class MusicListEvent implements ActionListener
???{
??? public void actionPerformed(ActionEvent e) {
???    JComboBox cb = (JComboBox)e.getSource();
???    String MusicName = (String)cb.getSelectedItem();
???    PlayingFileName = MusicName;
???    //updateLabel(petName);
???    Player.close();
???    //minim.stop();
???    //super.stop();
???    println(MusicName);
???    freshMusic();
???    
???    for(i=0;i

c) Display the information of a song which is playing

Variable declaration:

 

Minim minim;

AudioMetaData meta;

      Function:

?? void freshMusic() 
?????{
?????     ……
??????try {
?????      ……
?????      meta = Player.getMetaData();
?????      ……
?????     }   
??}

Draw ():

????//Display the information of a song which is playing
????  //You can set the following information of the songs in “Properties”
???? textFont(megaFont);
            text("File Name : " + meta.fileName(), 5, 25);
            //text("Length (in milliseconds): " + meta.length(), 5, 40);
            text("Length      :    " + meta.length()/60000+ ":" + meta.length()%60000/1000, 5, 45);
            text("Title         : " + meta.title(), 5, 65);
            text("Author     : " + meta.author(), 5, 85); 
            text("Album      : " + meta.album(), 5, 105);


d) Fast Fourier Transform of the music signal
Minim: FFT http://code.compartmental.net/tools/minim/manual-fft/
Variable declaration:
Minim minim;
FFT fft;
int localcolor[] = new int[3];
int avgColor;
float avgAvgColor;
int GetWave[] = {
  0, 2, 3
};
  

  Function:

?? void freshMusic() 
?????{
?????     ……
??????try {
?????      ……
?????      meta = Player.getMetaData();
?????      ……
?????     }   
??}

   Draw ():

???? //Display the information of a song which is playing
????  //You can set the following information of the songs in “Properties”
???? textFont(megaFont);
            text("File Name : " + meta.fileName(), 5, 25);
            //text("Length (in milliseconds): " + meta.length(), 5, 40);
            text("Length      :    " + meta.length()/60000+ ":" + meta.length()%60000/1000, 5, 45);
            text("Title         : " + meta.title(), 5, 65);
            text("Author     : " + meta.author(), 5, 85); 
            text("Album      : " + meta.album(), 5, 105);

d) Fast Fourier Transform of the music signal
Minim: FFT http://code.compartmental.net/tools/minim/manual-fft/
Variable declaration:
Minim minim;
FFT fft;
int localcolor[] = new int[3];
int avgColor;
float avgAvgColor;
int GetWave[] = {
  0, 2, 3
};
    Function:

?? void freshMusic() 
?????{
?????     ……
??????try {
?????    ……
?????    fft = new FFT(Player.bufferSize(), Player.sampleRate());
?????    fft.linAverages(100);
?????    ……
?????  } 
?????}

Draw ():

???? float centerFrequency = 0;
???? try {
????    fft.forward(Player.mix);
????    
????    int w = int(fft.specSize()/100);
????    for (int i = 0; i < fft.avgSize(); i++)
????    {
????       if ( mouseX >= i*w && mouseX < i*w + w )
????      {
????        centerFrequency = fft.getAverageCenterFrequency(i);
????        textFont(font);
????        textSize( 18 );        
????        fill(27, 128);
????        text("Linear Average Center Frequency: " + centerFrequency, 27, height45 - 110);
????        text("Frequency:" + fft.getAvg(i)*3, 27, height45 - 150);                 
????        fill(255, 64, 64);       
????      }
????      else
????      {
????          if (i == GetWave[0] || i == GetWave[1] || i == GetWave[2])  
????         {
????            //print("HeightVal:" + fft.getAvg(i) * 3 + "	");        
????            fill(154,192,205);
????         }else{
????            fill(27);
????         }
????      }
????      noStroke();
????      rect(i*w, height45, i*w + w/2, height45 - fft.getAvg(i)*spectrumScale);
????    }
????    
????    //localcolor[0]&localcolor[1]&localcolor[3]are used in CommWriter()
????    //These three values are the music signals sent to Arduino
????    localcolor[0] = constrain(int(fft.getAvg(GetWave[0]) *3), 0, 255);
????    localcolor[1] = constrain(int(fft.getAvg(GetWave[1]) * 3), 0, 255);
????    localcolor[2] = constrain(int(fft.getAvg(GetWave[2]) * 3), 0, 255);
????    print(localcolor[0]);
????    print("  ");
????    print(localcolor[1]);
????    print("  ");
????    println(localcolor[2]);
????  }
????  catch(Throwable err)  
????  {
????    println("Play Music Error!");
????  };

a) A Countdown Timer to show how much time is left of a song
Variable declaration:
PImage displayNote;
ControlP5 cp5;
ControlTimer clock;    
Textlabel timer;  
Setup():
displayNote = loadImage("note.png");
cp5 = new ControlP5(this);
clock = new ControlTimer();
timer = new Textlabel(cp5,"--",100,100);
clock.setSpeedOfTime(1);
   

  Function:

??void freshMusic() 
?????{
?????      ……
??????try {
?????      ……
?????      clock.reset();
?????      ……
?????     }   
??}

      Draw ():

??timer.setValue(clock.toString());
??          timer.draw(this);
??          timer.setPosition(450,275);

f) A Volume Controller
Minim: Controller http://code.compartmental.net/tools/minim/manual-controller/
Variable declaration:
ControlP5 cp5;
float Volume = 20;      
float setVol;  
Setup():
cp5.addSlider("Volume")
     .setColorValue(0xffffff00)
     .setPosition(20,360)
     .setRange(0,40)
     .setSize(200,20)
     .setNumberOfTickMarks(21)
;
Draw ():

???? try {
?????     ……
???????//The volume slider can adjust the value of gain
???????setVol=Volume-35;
??????Player .setGain(setVol);
???????……
????  }

 

Make Processing send music signal to Arduino 

g) A Play/Stop icon to control whether send music signal to Arduino
Part1: Setting for the icon image
Variable declaration:
PImage PlayButton;
PImage PlayOverButton;
PImage StopButton;
PImage StopOverButton;
int PicSizeX = 70;
int PicSizeY = 49;
int PicPositionSTX = 600 - 60;
int PicPositionSTY = 400 - 60;  
Setup():
PlayButton = loadImage("Play.png");
StopButton = loadImage("Stop.png");
PlayOverButton = loadImage("Play_over.png");
    StopOverButton = loadImage("Stop_over.png");


Function:

??// Switching between the buttons: 
??//playButton/playoverButton/stopButton/stopoverButton
??//Response to the mousePressed() function
??boolean StartState = false;
??boolean ButtonRegion = false;
??????public void ButtonImage(int x, int y)
??????{
??????if (mouseX > x && mouseX < (x + PicSizeX) && mouseY > y && mouseY < (y + PicSizeY)) { 
??????ButtonRegion  = true;
??????} else{
?????? ButtonRegion = false;
??????}
??????  if (StartState)  
??????  {
??????    if (ButtonRegion)  image(StopOverButton, x, y); 
??????    else  image(StopButton, x, y);
??????  }
??????  else  
??????  {
??????    if (ButtonRegion)  image(PlayOverButton, x, y);
??????    else  image(PlayButton, x, y);
??????  }
?????}
?????
?????// Use mouse to control whether send music signal to Arduino
?????String portChoise;
?????int BaudChoise;
?????void mousePressed()
?????{
?????  try {
?????    if (ButtonRegion)   //image button region
?????    {
?????      //portChoise = Serial.list()[1];
?????      if (!StartState)     
?????      {   
?????        StartState = true;
?????        portChoise = PortBox.getSelectedItem().toString();
?????        BaudChoise = Integer.parseInt(BaudBox.getSelectedItem().toString());
?????
?????        println(portChoise + "	" + BaudChoise);
?????
?????        ArduinoPort = new Serial(this, portChoise, BaudChoise);
?????      }
?????      else 
?????      {
?????        StartState = false;
?????        ArduinoPort.stop();
?????      }
?????    } 
?????  }
?????  catch(Throwable err)  
?????  {
?????    println("Error!");
?????  }
?????}  

Part2: Use CommWriter() to control the information sent to Arduino
Draw ():
PlayButton = loadImage("Play.png"); 


Function:

?????int[] WriteByte = new int[20];
??void CommWriter(int command)
??{
??  //int[] WriteByte = new int[20];
??  int Length = 4;
??
??  switch(command) {
??  case 'B':
??    WriteByte[0] = 'B';
??    WriteByte[1] = 0;
??    WriteByte[2] = 0;
??    WriteByte[3] = 0;
??    WriteByte[4] = 0x0a;
??    Length = 4;
??    break;
?? 
??  //localcolor[0]/localcolor[1]/localcolor[3] stores the music signal sent to Arduino 
??  case 'C':
??    WriteByte[0] = 'C';
??    WriteByte[1] = localcolor[0]; 
??    WriteByte[2] = localcolor[1];
??    WriteByte[3] = localcolor[2];
??    WriteByte[4] = 0x0a;
??    
??    Length = 4;
??    break;
??
??  default:
??    break;
??  }
??  //println("TransCommand!");
??
??
??  if (StartState)
??  {
??    try {
??      for (int i = 0;i <= Length ;i++)  ArduinoPort.write(WriteByte[i]);
??    }
??    catch(Throwable err)  
??    {
??      //println("Error!");
??    }
??  }
}

Processing Program
Attention:
  1. You need to add come songs to the “data” folder of your Processing program.
      A simple way to add a file in the data folder is to drag the file directly into the Processing window.
      You can also use the menu: click sketch Add File
  1. The font ArialMT–12.vlw can be downloaded at : https://github.com/ddf/Minim/blob/master/examples/Analysis/SoundSpectrum/data/ArialMT-12.vlw
      You should add this font into the data folder if you want to use it.
  1. Please make sure that you connect a ear plug or other Audio equipments as a output when you run the Processing program, otherwise the program will report an error.
Arduino Part
Libraries needed:
  • PumpSignal
  • colorLed
  • Metro 
The Arduino part has three main functions:
  1. Receive the music signal sent from Processing.
  1. Control two or three pumps to make them change the water flow according to the music signal. 
  1. Light six LEDs to make the water colorful.
Program:

#include //version 0.3
#include 
#include  

PumpSignal pump = PumpSignal();
colorLed pins = colorLed(9,10,11);
Metro ledMetro = Metro(2000);

byte newData[3];
 
int E1 = 5;       //M1 Speed Control
int M1 = 4;      //M1 Direction Control

int E2 = 6;       //M2 Speed Control
int M2 = 7;      //M2 Direction Control

void stop(void)                    //Stop
{
  digitalWrite(E1,LOW);
  digitalWrite(E2,LOW);
  Serial.begin(57600);   
  randomSeed(analogRead(3));  
}

void advance(char a, char b)          //Move forward
{
  analogWrite (E1,a);      //PWM Speed Control
  digitalWrite(M1,HIGH);  
  analogWrite (E2,b);      
  digitalWrite(M2,HIGH); 
}    

void setup(void) 
{ 
  pins.InitPins(); 
  int i;
  for(i=4;i<=7;i++)
    pinMode(i, OUTPUT); 
} 

int val[3];
int i = 0;
void loop(void) 
{
 pump.Run();
 //Receive the music signal sent from Processing
 if(pump.newCmd('C')){

    pump.getSerialCmd('C',newData);
//Control two pumps to make them change the water flow according to the music signal
  for(i=0;i<=1;i++){
    if(newData[i]>0&&newData[i]<=47){
       val[0] = map(newData[0],0,47,47,52); 
       val[1] = map(newData[2],0,50,50,55);
    }else{    
       val[0] = newData[0]; 
       val[1] = newData[2];
    }
  }
 }
  advance (val[0],val[1]);
   
//Light six LEDs to make the water colorful  
  if (ledMetro.check() == 1) { 
    pins.colorRGB(random(0,255),random(0,255),random(0,255));
  }
}

Connection Diagram:


Connection Instruction:
1) Connect two pumps to M1&M2;
2) A 25V-1000uf capacitance and a 50V-4.7uf capacitance should be connected to M1&M2;
3) You can solder several LEDs together and connect their public pins to Digital Pin9&Pin10&Pin11: Red à Pin9; Green à Pin10; Blue à Pin11

 

REVIEW