Trigger sound when data == x

Hi,
I would like to trigger sound when I receive data=0.
But sometimes It works, sometimes it doesn’t.
Maybe because my program doesn’t actualise itself enough quickly?

here my program

import processing.serial.*;  // import data from Arduino  
Serial myPort; // The serial port

float v0,v1,v2,v3,v4;

int x;
import ddf.minim.*;

Minim minim;
AudioSample kick;
AudioSample snare;

void setup()
{
  background (255);
   size(1000,800);
  
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[4], 115200);
 
  // Read bytes into a buffer until you get a linefeed (ASCII 10):
  myPort.bufferUntil('\n');
  
  minim = new Minim(this);

  // load BD.wav from the data folder
  kick = minim.loadSample( "BD.mp3", // filename
                            512      // buffer size
                         );
                         
  // An AudioSample will spawn its own audio processing Thread, 
  // and since audio processing works by generating one buffer 
  // of samples at a time, we can specify how big we want that
  // buffer to be in the call to loadSample. k
  // above, we requested a buffer size of 512 because 
  // this will make the triggering of the samples sound more responsive.
  // on some systems, this might be too small and the audio 
  // will sound corrupted, in that case, you can just increase
  // the buffer size.
  
  // if a file doesn't exist, loadSample will return null
  if ( kick == null ) println("Didn't get kick!");
  
  // load SD.wav from the data folder
  snare = minim.loadSample("SD.wav", 512);
  if ( snare == null ) println("Didn't get snare!");
}

void draw()
{
  background(0);
  stroke(255);
  
  // use the mix buffer to draw the waveforms.
  for (int i = 0; i < kick.bufferSize() - 1; i++)
  {
    float x1 = map(i, 0, kick.bufferSize(), 0, width);
    float x2 = map(i+1, 0, kick.bufferSize(), 0, width);
    line(x1, 50 - kick.mix.get(i)*50, x2, 50 - kick.mix.get(i+1)*50);
    line(x1, 150 - snare.mix.get(i)*50, x2, 150 - snare.mix.get(i+1)*50);
  }
   // Draw circles
  fill(25);
  ellipse(x, v0+250, 5, 5);
  fill(50);
  ellipse(x, v1+350, 5, 5);
    fill(75);
  ellipse(x, v2+450, 5, 5);
  fill(100);
  ellipse(x, v3+550, 5, 5);
 fill (125);
  ellipse(x, v4+650, 5, 5);
 
  // Update x position
  x++;
 
  // Refresh screen
  if (x > width) {
    background(255);
    x = 0;
  }
  
  
}

void keyPressed() 
{
  if ( key == 's' ) snare.trigger();
  if ( key == 'k' ) kick.trigger();
  if ( key == 'j' ) kick.trigger();
}

// serialEvent  method is run automatically by the Processing applet
// whenever the buffer reaches the byte value set in the bufferUntil()
// method in the setup():
void serialEvent(Serial myPort) {
 
  // read the serial buffer:
  String myString = myPort.readStringUntil('\n');
 
  // if you got any bytes other than the linefeed:
  myString = trim(myString);
  //println(myString);
 
  // split the string at the commas
  // and convert the sections into integers:
  float values[] = float(split(myString, ','));
 
  if (values.length > 0) {
    // ATTENTION LANCE ARDUINO pendant 5 sec puis Processing
    
 v0=  map (values[0], 0, 2774, 0, 36);
 v1=  map (values[1], 0, 2774, 0, 36);
 v2=  map (values[2], 0, 2774, 0, 36);
 v3=  map (values[3], 0, 2774, 0, 36);
 v4=  map (values[4], 0, 2774, 0, 36);
    
    println (v0);
    println (v1);
    println (v2);
    println (v3);
   
  }
  if (int (v0)==0) snare.trigger();
   if (int (v1)==0) snare.trigger();
  
    
}

I send this from Arduino

    for(uint8_t i = 0; i < NBMOTEURS; i++) { 
      Serial.print(position[i]); 
      Serial.print(", "); 
       
    } //Serial.println(""); 

  //  */
   Serial.println(); 
 
  } 

i don’t think so,
YOUR program action happens in the

void serialEvent(Serial myPort) {}

so not worry.


for the arduino communication, if you not show the code there,
minimal you should post the

println(myString);

best after a NOT NULL check.


but you do a

 if (values.length > 0) {

later, in where you do your data evaluation,
sadly the JOB

  if (int (v0)==0) snare.trigger();
   if (int (v1)==0) snare.trigger();

you do AFTER the related }
think what that means: you (retrigger) after ( as long as ) a

int (v0)==0

every time also when serial event sees a empty line… ( happens often…)

( no idea how MINIM deals with it )

so, better move that } down, after the two if’s.


just for understanding, what data arduino sends?
Ain’s are int 1023
but you get float 2774 .0 ?
and why you map down to 36?
and if you need int 36 anyhow why not use

int v0 = (int)map(values[0], 0, 2774, 0, 36);

for me your code means:

if ( values[0] < 77.0 )  snare.trigger();

is that what you need?

Thanks for your quick answer!
I have changed the program as you said but now, I still receive my 5 datas but only one v0 (the first) is mapped!

This value, v0 trig a sound but sometimes it doesn’t.
Actually I send position of a motor which go from 0 to 2774.
Then I map it in Processing from 0 to 36 (as 0 to 360°).
Each time my motor make a round, I want Processing trig a sound.
Maybe, sometimes v0 is not between (v0>=36|| v0<=0) ???
So what to do?

I have always my problem disabling my serial but I’ll see it later.

/**
  * This sketch demonstrates how to use the <code>loadSample</code> method of <code>Minim</code>. 
  * The <code>loadSample</code> method allows you to specify the sample you want to load 
  * with a <code>String</code> and optionally specify what you want the buffer size of the 
  * returned <code>AudioSample</code> to be. Minim is able to load wav files, au files, aif
  * files, snd files, and mp3 files. When you call <code>loadSample</code>, if you just 
  * specify the filename it will try to load the sample from the data folder of your sketch. 
  * However, you can also specify an absolute path (such as "C:\foo\bar\thing.wav") and the 
  * file will be loaded from that location (keep in mind that won't work from an applet). 
  * You can also specify a URL (such as "http://www.mysite.com/mp3/song.mp3") but keep in mind 
  * that if you run the sketch as an applet you may run in to security restrictions 
  * if the applet is not on the same domain as the file you want to load. You can get around 
  * the restriction by signing all of the jars in the applet.
  * <p>
  * An <code>AudioSample</code> is a special kind of file playback that allows
  * you to repeatedly <i>trigger</i> an audio file. It does this by keeping the
  * entire file in an internal buffer and then keeping a list of trigger points.
  * <code>AudioSample</code> supports up to 20 overlapping triggers, which
  * should be plenty for short sounds. It is not advised that you use this class
  * for long sounds (like entire songs, for example) because the entire file is
  * kept in memory.
  * <p>
  * Use 'k' and 's' to trigger a kick drum sample and a snare sample, respectively. 
  * You will see their waveforms drawn when they are played back.
  * <p>
  * For more information about Minim and additional features, 
  * visit http://code.compartmental.net/minim/
  */
import processing.serial.*;  // import data from Arduino  
Serial myPort; // The serial port

int v0 = 0;
int v1 = 0;
int v2 = 0;
int v3 = 0;
int v4 = 0;



int x;
import ddf.minim.*;

Minim minim;
AudioSample kick;
AudioSample snare;

void setup()
{
  background (255);
   size(1000,800);
  
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[4], 115200);
 
  // Read bytes into a buffer until you get a linefeed (ASCII 10):
  myPort.bufferUntil('\n');
  
  minim = new Minim(this);

  // load BD.wav from the data folder
  kick = minim.loadSample( "BD.mp3", // filename
                            512      // buffer size
                         );
                         
  // An AudioSample will spawn its own audio processing Thread, 
  // and since audio processing works by generating one buffer 
  // of samples at a time, we can specify how big we want that
  // buffer to be in the call to loadSample. k
  // above, we requested a buffer size of 512 because 
  // this will make the triggering of the samples sound more responsive.
  // on some systems, this might be too small and the audio 
  // will sound corrupted, in that case, you can just increase
  // the buffer size.
  
  // if a file doesn't exist, loadSample will return null
  if ( kick == null ) println("Didn't get kick!");
  
  // load SD.wav from the data folder
  snare = minim.loadSample("SD.wav", 512);
  if ( snare == null ) println("Didn't get snare!");
}

void draw()
{
  background(0);
  stroke(255);
  
  // use the mix buffer to draw the waveforms.
  for (int i = 0; i < kick.bufferSize() - 1; i++)
  {
    float x1 = map(i, 0, kick.bufferSize(), 0, width);
    float x2 = map(i+1, 0, kick.bufferSize(), 0, width);
    line(x1, 50 - kick.mix.get(i)*50, x2, 50 - kick.mix.get(i+1)*50);
    line(x1, 150 - snare.mix.get(i)*50, x2, 150 - snare.mix.get(i+1)*50);
  }
   // Draw circles
  fill(25);
  ellipse(x, v0+250, 5, 5);
  fill(50);
  ellipse(x, v1+350, 5, 5);
    fill(75);
  ellipse(x, v2+450, 5, 5);
  fill(100);
  ellipse(x, v3+550, 5, 5);
 fill (125);
  ellipse(x, v4+650, 5, 5);
 
  // Update x position
  x++;
 
  // Refresh screen
  if (x > width) {
    background(255);
    x = 0;
  }
  
  
}

void keyPressed() 
{
  if ( key == 's' ) snare.trigger();
  if ( key == 'k' ) kick.trigger();
  if ( key == 'j' ) kick.trigger();
}

// serialEvent  method is run automatically by the Processing applet
// whenever the buffer reaches the byte value set in the bufferUntil()
// method in the setup():
void serialEvent(Serial myPort) {
 
  // read the serial buffer:
  String myString = myPort.readStringUntil('\n');
 
  // if you got any bytes other than the linefeed:
  myString = trim(myString);
  println(myString);
 
  // split the string at the commas
  // and convert the sections into integers:
  int values[] = int(split(myString, ','));
 
  if (values.length > 0) {
    // CARFUL when problem disabling serial port, stop, unplugge, play again
    
 v0 = (int)map(values[0], 0, 2774, 0, 36);
 v1 = (int)map(values[1], 0, 2774, 0, 36);
 v2 = (int)map(values[2], 0, 2774, 0, 36);
 v3 = (int)map(values[3], 0, 2774, 0, 36); 
 v4 = (int)map(values[4], 0, 2774, 0, 36);
    
   println (v0); println (v1); println (v2); println (v3);
  
   if (v0>=36|| v0<=0) snare.trigger();
 //  if (int (v1)==0) snare.trigger();
   
} 
  
}

I send this from Arduino

    for(uint8_t i = 0; i < NBMOTEURS; i++) { 
      Serial.print(position[i]); 
      Serial.print(", "); 
       
    } //Serial.println(""); 

  //  */
   Serial.println(); 
 
  } 

I took a quick look…

v0 = (int)map(values[0], 0, 2774, 0, 36);
So v0 is 0 to 36

if (v0>=36 || v0<=0) snare.trigger();
This is triggering if v0 is <= 0 or v0 is >= 36

You will only trigger on 0 or 36 according to mapping.

:slight_smile:

and in your serial event loop you now use the

println(myString);
 if (values.length > 0) {
   //...
   println (v0); println (v1); println (v2); println (v3);

can you please post that resulting console output here

First I have those datas

[0] "/dev/cu.BeatsPill-SPPDev-1"
[1] "/dev/cu.Bluetooth-Incoming-Port"
[2] "/dev/cu.JBLFlip3-SPPDev"
[3] "/dev/cu.UEBOOM-LWACP"
[4] "/dev/cu.usbmodem14201"
[5] "/dev/tty.BeatsPill-SPPDev-1"
[6] "/dev/tty.Bluetooth-Incoming-Port"
[7] "/dev/tty.JBLFlip3-SPPDev"
[8] "/dev/tty.UEBOOM-LWACP"
[9] "/dev/tty.usbmodem14201"
397, 145, 0, 0,
5
0
0
0

Error, disabling serialEvent() for /dev/cu.usbmodem14201
null

Then, I stop the Processing program, I unplug the serial port, I re plug it, and I start again and I have those datas




2771, 2768, 714, 24, 1975,
35
0
0
0
0
2771, 2768, 714, 24, 1975,
35
0
0
0

As you can see only the first data value[0] is mapped v0=35
but the others stay at 0 :face_with_raised_eyebrow:

I didn’t have those problem before.

Also, if I let the program goes on a few time, my computer MacBookPro Retina
2,6 GHz Intel Core i5 and 8 Go 1600 MHz DDR3 becomes hot.

Thanks for your light

https://processing.org/reference/trim_.html
" Removes whitespace characters from the beginning and end of a String."

  String myString ="500, 1000, 1500, 2000, 2500\r\n";
  println(myString);
 
  myString = trim(myString);
  println(myString);
  

Don’t send spaces or trim() them from each sub string in array:

  String values[] = split(myString, ',');  
  int v0 = (int) map(int(trim(values[0])), 0, 2774, 0, 36);

Or like this:

  int values[] = int(trim(split(myString, ','))); 
  int v0 = (int) map(values[0], 0, 2774, 0, 36);

Also consider:
http://javadevnotes.com/java-float-to-int

:slight_smile:

Also, don’t use AudioSample for short, repeat-triggered audio events. Use a Sampler instead.

http://code.compartmental.net/minim/sampler_class_sampler.html

Sampler is the UGen version of AudioSample and is the preferred method of triggering short audio files. You will also find Sampler much more flexible, since it provides ways to trigger only part of a sample, and to trigger a sample at different playback rates. Also, unlike AudioSample, a Sampler lets you specify how many voices (i.e. simultaneous playbacks of the sample) should have.

2 Likes

I have changed the program like that

void serialEvent(Serial myPort) {
 
  // read the serial buffer:
  String myString = myPort.readStringUntil('\n');
 
  // if you got any bytes other than the linefeed:
  
  println(myString);
 
  int values[] = int(trim(split(myString, ','))); 
   v0 = (int) map(values[0], 0, 2771, 0, 36);
   v1 = (int) map(values[1], 0, 2771, 0, 36);
   v2 = (int) map(values[2], 0, 2771, 0, 36);
   v3 = (int) map(values[3], 0, 2771, 0, 36);
   v4 = (int) map(values[4], 0, 2771, 0, 36);

    println (v0); println (v1); println (v2); println (v3); println (v4);  
}

I receive the 5 datas, they are well mapped. :slight_smile: But I have still the same problem by receiving datas disabling serialEvent() for /dev/cu.usbmodem14201
So i stop the program, unplugged, plug the serial again and restart and it works.

An other strange thing. Why when I stop the program in Processing, my program in Arduino stop and restart(while Arduino should receive no information)? I have got the same “bug” in Arduino when I want to see serial data with the monitor, my program re start itself

for the mac book serial

  • /dev/cu.
  • /dev/tty.

i have no idea,

but that a arduino ( uno ) reboots
at arduino IDE monitor ( serial) connect AND disconnect
is true.

now that does not need to be true with other serial software
( where modem settings possible )
and JAVA serial also might show OS dependency /
processing actually not deal with serial directly.
but practice is that you connect to a arduino only once in a processing session
and possibly have to wait out some boot / startup delay…

Ok,
Now I can trig sound and sometimes sounds are not trigged. Maybe because datas go above 349 directly to 0?

I put the end of the program

void serialEvent(Serial myPort) {
 
  // read the serial buffer:
   String myString = myPort.readStringUntil('\n');
 
  // if you got any bytes other than the linefeed:
  
  println(myString);
 
  int values[] = int(trim(split(myString, ','))); 
    // ATTENTION LANCE ARDUINO pendant 5 sec puis Processing
    
 v0 = (int)map(values[0], 0, 2771, 0, 360);
 v1 = (int)map(values[1], 0, 2771, 0, 360);
 v2 = (int)map(values[2], 0, 2771, 0, 360);
 v3 = (int)map(values[3], 0, 2771, 0, 360); 
 v4 = (int)map(values[4], 0, 2771, 0, 360);
    
   println (v0); println (v1); println (v2); println (v3);
  
   if (v0>=350) snare.trigger();
   if (v1>=350) snare.trigger();
   if (v2>=350) snare.trigger();
   if (v3>=350) snare.trigger();
   if (v4>=350) snare.trigger();
   
}

Hello Jeremy,

I have mixed my program to trig sample into the example of DrumMachine in order to trig samples later. But I have always on the console

[0] "/dev/cu.BeatsPill-SPPDev-1"
[1] "/dev/cu.Bluetooth-Incoming-Port"
[2] "/dev/cu.JBLFlip3-SPPDev"
[3] "/dev/cu.UEBOOM-LWACP"
[4] "/dev/cu.usbmodem14201"
[5] "/dev/tty.BeatsPill-SPPDev-1"
[6] "/dev/tty.Bluetooth-Incoming-Port"
[7] "/dev/tty.JBLFlip3-SPPDev"
[8] "/dev/tty.UEBOOM-LWACP"
[9] "/dev/tty.usbmodem14201"
2771, 0, 0, 0, 1, 

360
0
0
0
Error, disabling serialEvent() for /dev/cu.usbmodem14201
null

I have tried to stop program, unplug the serial port, plug it again and re start the program but I have always
Error, disabling serialEvent() for /dev/cu.usbmodem14201
null.

But I can use the sequencer properly.

I put the program below

import processing.opengl.*;

/**
  * This sketch is a more involved use of AudioSamples to create a simple drum machine. 
  * Click on the buttons to toggle them on and off. The buttons that are on will trigger 
  * samples when the beat marker passes over their column. You can change the tempo by 
  * clicking in the BPM box and dragging the mouse up and down.
  * <p>
  * We achieve the timing by using AudioOutput's playNote method and a cleverly written Instrument.
  * <p>
  * For more information about Minim and additional features, 
  * visit http://code.compartmental.net/minim/
  */


import ddf.minim.*;
import ddf.minim.ugens.*;

Minim       minim;
AudioOutput out;

Sampler     kick;
Sampler     snare;
Sampler     hat;

boolean[] hatRow = new boolean[16];
boolean[] snrRow = new boolean[16];
boolean[] kikRow = new boolean[16];

ArrayList<Rect> buttons = new ArrayList<Rect>();

int bpm = 120;

int beat; // which beat we're on

// here's an Instrument implementation that we use 
// to trigger Samplers every sixteenth note. 
// Notice how we get away with using only one instance
// of this class to have endless beat making by 
// having the class schedule itself to be played
// at the end of its noteOff method. 
class Tick implements Instrument
{
  void noteOn( float dur )
  {
    if ( hatRow[beat] ) hat.trigger();
    if ( snrRow[beat] ) snare.trigger();
    if ( kikRow[beat] ) kick.trigger();
  }
  
  void noteOff()
  {
    // next beat
    beat = (beat+1)%16;
    // set the new tempo
    out.setTempo( bpm );
    // play this again right now, with a sixteenth note duration
    out.playNote( 0, 0.25f, this );
  }
}

// simple class for drawing the gui
class Rect 
{
  int x, y, w, h;
  boolean[] steps;
  int stepId;
  
  public Rect(int _x, int _y, boolean[] _steps, int _id)
  {
    x = _x;
    y = _y;
    w = 14;
    h = 30;
    steps = _steps;
    stepId = _id;
  }
  
  public void draw()
  {
    if ( steps[stepId] )
    {
      fill(0,255,0);
    }
    else
    {
      fill(255,0,0);
    }
    
    rect(x,y,w,h);
  }
  
  public void mousePressed()
  {
    if ( mouseX >= x && mouseX <= x+w && mouseY >= y && mouseY <= y+h )
    {
      steps[stepId] = !steps[stepId];
    }
  }
}
import processing.serial.*;  // import data from Arduino  
Serial myPort; // The serial port

int v0 = 0;
int v1 = 0;
int v2 = 0;
int v3 = 0;
int v4 = 0;

int x;


void setup()
{
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[4], 115200);
 
  // Read bytes into a buffer until you get a linefeed (ASCII 10):
  myPort.bufferUntil('\n');
  
  
  
  size(395, 200);
  minim = new Minim(this);
  out   = minim.getLineOut();
  
  // load all of our samples, using 4 voices for each.
  // this will help ensure we have enough voices to handle even
  // very fast tempos.
  kick  = new Sampler( "BD.wav", 4, minim );
  snare = new Sampler( "SD.wav", 4, minim );
  hat   = new Sampler( "CHH.wav", 4, minim );
  
  // patch samplers to the output
  kick.patch( out );
  snare.patch( out );
  hat.patch( out );
  
  for (int i = 0; i < 16; i++)
  {
    buttons.add( new Rect(10+i*24, 50, hatRow, i ) );
    buttons.add( new Rect(10+i*24, 100, snrRow, i ) );
    buttons.add( new Rect(10+i*24, 150, kikRow, i ) );
  }
  
  beat = 0;
  
  // start the sequencer
  out.setTempo( bpm );
  out.playNote( 0, 0.25f, new Tick() );
}

void draw()
{
  background(0);
  fill(255);
  //text(frameRate, width - 60, 20);
  
  for(int i = 0; i < buttons.size(); ++i)
  {
    buttons.get(i).draw();
  }
  
  stroke(128);
  if ( beat % 4 == 0 )
  {
    fill(200, 0, 0);
  }
  else
  {
    fill(0, 200, 0);
  }
    
  // beat marker    
  rect(10+beat*24, 35, 14, 9);
}

void mousePressed()
{
  for(int i = 0; i < buttons.size(); ++i)
  {
    buttons.get(i).mousePressed();
  }
}

void serialEvent(Serial myPort) {
 
  // read the serial buffer:
   String myString = myPort.readStringUntil('\n');
 
  // if you got any bytes other than the linefeed:
  
  println(myString);
 
  int values[] = int(trim(split(myString, ','))); 
    // ATTENTION LANCE ARDUINO pendant 5 sec puis Processing
    
 v0 = (int)map(values[0], 0, 2771, 0, 360);
 v1 = (int)map(values[1], 0, 2771, 0, 360);
 v2 = (int)map(values[2], 0, 2771, 0, 360);
 v3 = (int)map(values[3], 0, 2771, 0, 360); 
 v4 = (int)map(values[4], 0, 2771, 0, 360);
    
   println (v0); println (v1); println (v2); println (v3);
  
   if (v0>=350) snare.trigger();
   if (v1>=350) snare.trigger();
   if (v2>=350) snare.trigger();
   if (v3>=350) snare.trigger();
   if (v4>=350) snare.trigger();
   
   
}

Sorry I haven’t been working with Arduino lately and don’t have one on-hand to test serial lately – hopefully an Arduino-serial user can give you more feedback on that aspect of your problem.

again, that is not so much about arduino, more
mac book serial

why you connect to .cu [4] and not .tty [9]

see also
https://stackoverflow.com/questions/8632586/macos-whats-the-difference-between-dev-tty-and-dev-cu ,

as here your mac hardware NOT available,
i could only test with win7 or Raspbian.