Go Down

Topic: Using serial data from Arduino to play mp3 files in Processing (Read 2551 times) previous topic - next topic

lf07cj

Hello,
I'm a newbie and don't have much experience programming.  I'd like to expand on my last project where I used the serial data from an accelerometer attached to the body, to create sound through a piezo buzzer.  Now, I'd like to use this data to play mp3 files in Processing.  I know how to play an audio file in Processing but I don't know how to bring in the arduino data and link it with Processing.

Any help would be much appreciated.

Here is my Arduino code:

Code: [Select]
*/

// these constants describe the pins. They won't change:

const int sensorPinx = 2;                  // x-axis of the accelerometer
const int sensorPiny = 3;                  // y-axis
const int sensorPinz = 4;                  // z-axis (only on 3-axis models)
int sensorValuex;
int sensorValuey;
int sensorValuez;
int speakerPin = 9;         // speaker connected to digital pin 9

void setup()
{
  pinMode(sensorPinx, INPUT);         // sets the sensorPin to be an input
  pinMode(sensorPiny, INPUT);         // sets the sensorPin to be an input
  pinMode(sensorPinz, INPUT);         // sets the sensorPin to be an input

  pinMode(speakerPin, OUTPUT);         // sets the speakerPin to be an output
  Serial.begin(9600); // initialize the serial communications:
}

void loop()
{
  sensorValuex = analogRead(sensorPinx);         // read the value from the sensor

  sensorValuey = analogRead(sensorPiny);         // read the value from the sensor

  sensorValuez = analogRead(sensorPinz);         // read the value from the sensor

  // print the sensor values:
  Serial.print(analogRead(sensorPinx));
  // print a tab between values:
  Serial.print("\t");
  Serial.print(analogRead(sensorPiny));
  // print a tab between values:
  Serial.print("\t");
  Serial.print(analogRead(sensorPinz));
  Serial.println();

  // delay before next reading:
  delay(100);

  if (sensorValuex >=50 && sensorValuex <=100) { // body not moving
    beep(speakerPin,2093,100);     //C
    if (sensorValuex >=300 && sensorValuex <=400);
    beep(speakerPin,2637,500);     //E
     if (sensorValuex >=425 && sensorValuex <=500);
        beep(speakerPin,3136,100);     //G
  }
  else
{
   
    digitalWrite(speakerPin, LOW);  //turn speaker on


  }
}  // scale(); 
 

void beep (unsigned char speakerPin, int frequencyInHertz, long timeInMilliseconds) {     
  int x;     
  long delayAmount = (long)(1000000/frequencyInHertz);
  long loopTime = (long)((timeInMilliseconds*1000)/(delayAmount*2));
  for (x=0;x<loopTime;x++)     
  {     
    digitalWrite(speakerPin,HIGH);
    delayMicroseconds(delayAmount);
    digitalWrite(speakerPin,LOW);
    delayMicroseconds(delayAmount);
  }     


void scale () {     
  beep(speakerPin,2093,100);     //C:
   beep(speakerPin,2349,100);     //D
   beep(speakerPin,2637,500);     //E
   beep(speakerPin,2793,500);     //F
   beep(speakerPin,3136,100);     //G
   beep(speakerPin,3520,500);     //A
   beep(speakerPin,3951,500);     //B
   beep(speakerPin,4186,500);     //C */
}       


Here is my Processing code:
Code: [Select]


*/
import processing.serial.*;
//import cc.arduino.*;

//Arduino arduino;

//Serial myPort;
String serialString;

import ddf.minim.*;

AudioPlayer player;
Minim minim;

void setup()
{
  size(512, 200, P2D);

  minim = new Minim(this);
 
  // load a file, give the AudioPlayer buffers that are 1024 samples long
  // player = minim.loadFile("song.mp3");
 
  // load a file, give the AudioPlayer buffers that are 2048 samples long
  player = minim.loadFile("song.mp3", 2048);
  // play the file
  player.play();
    player.loop();
}

void draw()
{
  background(0);
  stroke(255);
  // draw the waveforms
  // the values returned by left.get() and right.get() will be between -1 and 1,
  // so we need to scale them up to see the waveform
  // note that if the file is MONO, left.get() and right.get() will return the same value
  for(int i = 0; i < player.left.size()-1; i++)
  {
    line(i, 50 + player.left.get(i)*50, i+1, 50 + player.left.get(i+1)*50);
    line(i, 150 + player.right.get(i)*50, i+1, 150 + player.right.get(i+1)*50);
  }
}

void stop()
{
  // always close Minim audio classes when you are done with them
  player.close();
  minim.stop();
 
  super.stop();
}

PaulS

Set that Processing sketch aside, for now. Look at the example Processing sketches for receiving serial data. When you get one of them working, which really should be no problem (connecting to the correct serial port is the hardest part), you can modify that example to parse the data, and make decisions based on that data.

Being an engineer and a software developer, not an artist or musician, I can't see any relationship between periodic acceleration data and which mp3 file to play, but that is not the issue here.

PaulS

Quote
I have successfully completed example #8 from the "Getting Started with Processing" and can read the serial data from my sensor

So far, so good.

Quote
in a wave

Oops, did I miss a turn somewhere?

Quote
but how do I isolate ranges so that I can make my "if" statements?  Do I need to convert this data back into a numeric form?

If tests involve conditions, like ==, >=, <=, >, or <. These require numeric values. However, the value that you are sending from the Arduino IS a numeric value, so, no, you don't need to convert a numeric value to a numeric form.

I'm not sure what you are trying to do here, so I can't offer specific advice.

PaulS

In the Processing application, you have this statement:
Code: [Select]
    val = port.read();          // read it and store it in val
It is reading, in the draw() function, which is called in an endless loop, the data that the Arduino sends using these statements:
Code: [Select]
  Serial.print(analogRead(sensorPinx));
  // print a tab between values:
  Serial.print("\t");
  Serial.print(analogRead(sensorPiny));
  // print a tab between values:
  Serial.print("\t");
  Serial.print(analogRead(sensorPinz));
  Serial.println();

That you can't make heads or tails of the data makes sense, since the data being sent by the Arduino is ascii data. If the accelerometers returned 175, 280, and 950, you are sending "175\t280\950\n\r" to the serial port, and reading '1', '7', '5', '\t', '2', '8', '0', '\t', '9', '5', '0', '\n, and '\r', and playing connect the dots with those values as though they were numbers.

Quote
I was able to bring in the data but I only see it visually in a moving "wave" pattern.  This is great because I can visually see the activity of the accelerometer

Nope, sorry, not even close.

You will need to change the Processing application. There is a bufferUntil() method in the Arduino class that can be used to define when the serialEvent method is called. In that method, you need to read all the serial data:
Code: [Select]
  String myString = myPort.readStringUntil('\n');
Then, parse the string, to get the x, y, and z values as strings, and convert the strings to ints:
    int sensors[] = int(split(myString, '\t'));
The result is an array of ints that correspond to what the Arduino sent.

You need to be plotting these three values to see which ones might be interesting.

My doubt, though, is that none of them will be, since an accelerometer measures a change in velocity with respect to time, and you are throwing the time portion of the data away. All you have left is the instantaneous change in velocity. Whether that is useful, or not, for controlling the music, I don't know. It would certainly not be useful for controlling an airplane, as the sensor is really intended to.

Go Up