Minim: Play a random song out of an array

Hey!
I’m trying to make a sketch that plays a random sound out of a pre-loaded AudioPlayer array in certain for loop conditions.
My problem is that for some reason ALL 3 items in the array play at once when I use – (int) random(3) –

Any suggestions?
Code is as follows:

import ddf.minim.*;
import ddf.minim.effects.*;

float start, runtime;
PImage earth, angry, happy, neutral;
PShape globe;
Minim minim;
AudioPlayer[] playlistGood;
AudioPlayer[] playlistBad;

void setup(){
  size(1200,800, P3D);
  background(32);
  start = millis();

   minim = new Minim(this);
 playlistGood = new AudioPlayer[3];
 playlistGood[0] = minim.loadFile("bestfriends2.mp3");
 playlistGood[1] = minim.loadFile("changeworld.mp3");
 playlistGood[2] = minim.loadFile("bus.mp3");
 
 playlistBad = new AudioPlayer[3];
 playlistBad[0] = minim.loadFile("acting2.mp3");
 playlistBad[1] = minim.loadFile("composting.mp3");
 playlistBad[2] = minim.loadFile("grandchildren.mp3");
 
 
 angry = loadImage("angry.JPG");
 happy = loadImage("happy.JPG");
 neutral = loadImage("neutral.JPG");
   
}

void draw(){
  background(32);
  //smooth();
  lights();
  runtime = millis() - start;
  
 

//sound/visual changes depending on time and position of person
if (mouseX > 1100) {
  earth = angry;
  playlistGood[0].rewind();
  playlistGood[1].rewind();
  playlistGood[2].rewind();
   playlistBad[(int) random(3)].play();

} else if ((mouseX < 1100) && (runtime > 5000)){
  earth = happy;
  playlistBad[0].rewind();
  playlistBad[1].rewind();
  playlistBad[2].rewind();
    playlistGood[(int)random(3)].play();
  
} else {
  println("walking");
  earth = neutral;
}

//reset timer after 15 seconds of inaction
if (runtime >= 20000){
  start = millis();
}
  println("runtime:" + runtime);

  //DRAW GLOBE
  translate(width/2, height/2);
  rotateX(0.2);
  //follow mouse movements
  rotateY(mouseX * 0.002);
  globe = createShape(SPHERE, 300);
  globe.setTexture(earth);
  globe.setStroke(false);
  shape(globe);
  
}
1 Like

i cut your main program flow out and put in prints:

float start, runtime;
void setup() {
  size(1200,100, P3D);
  start = millis();
}
 int loop = 0;
 
void draw() {
  loop++;
  runtime = millis() - start;
  if (mouseX > 1100) {
    println(loop+" > 1100 "+(int)random(3));
  } else if ((mouseX < 1100) && (runtime > 5000)) {
    println(loop+" < 1100 &&  runtime > 5000 "+(int)random(3));
  } else {
    println(loop+" walking");
  }
  if (runtime >= 20000) {
    start = millis();
    println(loop+" runtime >= 20000");
  }
}


now you see what you are doing to the computers audio player!

1 Like

Yeesh… What a train wreck! Yes I see now what it’s doing. Actually that’s what I thought it was going to do even when it was just playing one song - it just didn’t show it I guess!

How do I get around this?
Does it need to pick the songs outside of the for loop… even outside of draw? I’m not sure how I would go about doing this. They still need to play from the start when activated by the - for - conditions.

-a- learn to make a good ?toggle? button ( mousePressed ) logic
-b- at setup start all song with .loop and .pause
and the toggle logic for one song would be

  if ( groove.isPlaying() )     groove.pause();
  else                          groove.loop();

while still need to pause all others.

1 Like

I’m sorry, I don’t understand this at all…

So all songs need to be in setup as

if ( song1.isPlaying() )     song1.pause();
  else                          song1.loop();

if ( song2.isPlaying() )     song2.pause();
  else                          song2.loop();

?
I know (some) mousePressed logic but I don’t know how to apply that to mouseOver (or in this case torsoX coordinates)

Would you then still use .play in the if loops?

1 Like

no, that would be the logic to toggle one song, like from toggle button press

for more songs
-a- need to use the array with that logic AND
-b- take care of all other songs .pause besides the one you started with .loop

no, if you have a logic to start stop like in mousePressed keyPressed
a .play in draw would overwrite that?
and it would not say .play, it would say
.play.play.play.play.play.play.play.play.play.play.play.play.play.play.play.play
that you should have understood from my above version of your code.

i expected you show us some button code:

a rectangle with mouse over logic, boolean status memory and indication fill green or blue for run stop
and a mousePressed() handling that button logic

1 Like

Colour me confused…

1 Like

try this code

// https://discourse.processing.org/t/minim-play-a-random-song-out-of-an-array/14683

import ddf.minim.*;
import ddf.minim.effects.*;

Minim minim;
AudioPlayer[] playlistGood;

void setup() {
  size(800, 800, P3D);
  minim = new Minim(this);
  playlistGood = new AudioPlayer[2];
  playlistGood[0] = minim.loadFile("groove0.mp3");
  playlistGood[1] = minim.loadFile("groove1.mp3");

  for ( int i = 0; i < playlistGood.length; i++ ) {
    playlistGood[i].loop();
    playlistGood[i].pause();
  }
}

// button config
int b1x=700, b1y=100, b1w=80, b1h=30;
boolean set1 = false;
int b2x=700, b2y=200, b2w=80, b2h=30;
boolean set2 = false;
// mouse over rect function
boolean over(int x, int y, int w, int h) {
  if (  
    ( mouseX > x ) && ( mouseX < ( x + w ) ) && 
    ( mouseY > y ) && ( mouseY < ( y + h ) ) 
    )  return true;
  return false;
}

void draw_button() {
  strokeWeight(3);
  // button 1
  if ( over(b1x, b1y, b1w, b1h) ) stroke(200, 0, 200);     // border color
  else                            stroke(0, 200, 200);
  if ( set1 )   fill(0, 200, 0);                           // status fill color
  else          fill(0, 0, 200);
  rect(b1x, b1y, b1w, b1h);
  // button 2
  if ( over(b2x, b2y, b2w, b2h) ) stroke(200, 0, 200);     // border color
  else                            stroke(0, 200, 200);
  if ( set2 )   fill(0, 200, 0);                           // status fill color
  else          fill(0, 0, 200);
  rect(b2x, b2y, b2w, b2h);
}

void draw() {
  background(200, 200, 0);
  draw_button();
}

void mousePressed() {
  if ( over(b1x, b1y, b1w, b1h) ) {                          // button 1
    set1 = ! set1;
    if ( set1 ) {
      set2 = false;                                          // make option group logic unset others
      play_only_one(0);
    } else {
      pause_only_one(0);
    }
  }
  if ( over(b2x, b2y, b2w, b2h) ) {                          // button 2
    set2 = ! set2;
    if ( set2 ) {
      set1 = false;                                          // make option group logic unset others
      play_only_one(1);
    } else {
      pause_only_one(1);
    }
  }
}

void play_only_one(int j ) {
  for ( int i = 0; i < playlistGood.length; i++ ) {
    if ( ! playlistGood[i].isPlaying() && ( i == j ) ) {
      playlistGood[i].loop();  // if not play, start this one
      println("start "+j);
    } else playlistGood[i].pause();                                               // stop the rest
  }
}

void pause_only_one(int j ) {
  if ( playlistGood[j].isPlaying() ) {
    playlistGood[j].pause();
    println("stop "+j);
  }
}


i did NOT use class …
and only the song array ( like you have )
so the buttons are very manual…
but as a first step easy to understand, esp note the OVER function

it is not a random song play, it is a idea for one button for one song structure…
so for your idea need to change.
i wanted to show better buttons and the play one song logic.

1 Like