A sound play exemplar please?

I’ve spent the last several days scouring the web for WORKING examples of playing .mp3 and .wav files in Processing for Android.

Most of the examples no longer work or have ‘deprecated function’ on one of the classes. If I see another ‘AssetDescriptor getAssets() not found’ error, I may just slit my throat!

If someone could please post an example of being able to play a sound file in a processing app created with Android mode in processing I’d really appreciate it. And if you have an example that allows multi threading of sounds in processing for Android that would be fantastic!

Thank you for your consideration. This is a very helpful forum and a great community.

Best wishes,

Gord

1 Like

Hi Gord

Could you post some of the links of code you tried? Cassette is a library that was working before albeit with some limitations. Other than that, MediaPlayer seems to be the way to go. Related to MT, it is hard to provide an example without knowing the final outcome. You can take the lead to provide more details, or do a quick google search on current code available in Android suitable for your needs, posted here and we could produce a code that could be used in Processing Android mode.

Kf

1 Like

Hi Kf:

I’ve been trying everything I can find on the net.

This one has one sound specified, but it plays ALL the sounds in the data folder even though they’re not specified anywhere in the code.

Any suggestions you can make are appreciated.

Thank you very much.

Gord

import android.media.MediaPlayer;
import android.content.res.AssetFileDescriptor;
import android.content.Context;
import android.app.Activity;

MediaPlayer mp;
Context context; 
Activity act;
AssetFileDescriptor afd;

void setup() {
  act = this.getActivity();
  context = act.getApplicationContext();
  try {
    mp = new MediaPlayer();
    afd = context.getAssets().openFd("fogleg09.mp3");//which is in the data folder
    println("Successfully loaded audio file");
    mp.setDataSource(afd.getFileDescriptor());
    mp.prepare();
  } 
  catch(IOException e) {
    println("file did not load");
  }
  mp.start();
};

void draw() {
}

public void pause() {
  super.pause();
  if (mp !=null) {
    mp.release();
    mp = null;
  }
};

public void stop() {
  super.stop();
  if (mp !=null) {
    mp.release();
    mp = null;
  }
};
1 Like

I also tried:

import apwidgets.*;
APMediaPlayer player;

void setup()
{
  player = new APMediaPlayer(this);

  // SOUND FILE IS LOCATED IN THE '/data' FOLDER
  player.setMediaFile("fogleg09.mp3");
}

void mousePressed()
{
  player.start();
}

As soon as it launches I get the message, “Sorry, the application has stopped.”

1 Like

Hi Gord

You need to learn how to format your code in the forum. It is easy. Enclose your code using three back ticks like this:

```java
[<Your Code>]
```

You can change java for any other language (C, python, etc.)

****EDIT
Related to your last post. I believe apwidgets is not being supported so I am not sure if it will work. I have also tested your code. You can see it at the end of this post. I just edited this post to talk about your two examples above.

Back to your question. This link provides some code: Using Android MediaPlayer to play sound. - Processing 2.x and 3.x Forum

This next code is tested using P3.37 and Android Mode v4.0.1 which is from the previous link, slightly modified and tested on Samsung Galaxy S8 running on Oreo(Android version 8.0 / API 26). Make sure your mp3 file is in the data folder.

import android.media.MediaPlayer;
import  android.content.res.Resources;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.content.Context;
import android.app.Activity;
import android.os.Bundle;
 
MediaPlayer snd = new MediaPlayer();
//AssetManager assets = this.getAssets();
AssetFileDescriptor fd;
Context context;
Button bPlay;
Activity act;
 
void setup()
{
  colorMode(HSB);
  size(800, 800);
  act = this.getActivity();
  context = act.getApplicationContext();
  try {
 
    fd = context.getAssets().openFd("test-sound.mp3");
    snd.setDataSource(fd.getFileDescriptor(),fd.getStartOffset(), fd.getLength());
  }
  catch (IllegalArgumentException e) {
    e.printStackTrace();
  }
  catch (IllegalStateException e) {
    e.printStackTrace();
  } 
  catch (IOException e) {
    e.printStackTrace();
  }
 
  bPlay = new Button(width/2, height/2, 500, color(0, 125, 255));
}
 
void draw()
{
  background(210);
  bPlay.draw();
  textSize(30);
  textAlign(CENTER);
  fill(0, 21, 75);
  text("Press for replacement", width/2, height/2);
}
 
void mousePressed()
{
  if (bPlay.buttonCheck() && !snd.isPlaying()) {
    bPlay.c = color(0, 125, 220);
    try {
      snd.prepare();
      snd.start();
      //fd = context.getAssets().openFd("Ni-"+(int)random(1, 22)+".mp3");
      //snd.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
 
    }
    catch (IllegalArgumentException e) {
      e.printStackTrace();
    }
    catch (IllegalStateException e) {
      e.printStackTrace();
    } 
    catch (IOException e) {
      e.printStackTrace();
    }
    //fd = context.getAssets().openFd("Ni-"+(int)random(1, 22)+".mp3");
  }
}
 
void mouseReleased()
{
  bPlay.c = color(0, 125, 255);
 
}
 

 
 
////////////
 
class Button
{
  int x, y, w, h, r;
  color c;
 
  Button(int x, int y, int w, int h, color c) //rectangular buttons
  {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.c = c;
  }
  Button(int x, int y, int r, color c) //circular buttons
  {
    this.x = x;
    this.y = y;
    this.r = r;
    this.c = c;
  }
 
  void draw()
  {
    ellipseMode(CENTER);
    noStroke();
    fill(c);
    rect(x, y, w, h);
    ellipse(x, y, r, r);
  }
 
  boolean buttonCheck()
  {
    boolean result = false;
    float disX = x - mouseX;
    float disY = y - mouseY;
    if (sqrt(sq(disX) + sq(disY)) < r/2) result = true;
    return result;
  }
}



//===========================================================================
// ANDROID ACTIVITY LIFECYCLE'S FUNCTIONS:


//  @@@@@@@@@@@@
@Override 
  public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
}

//  @@@@@@@@@@@@
@Override 
  public void onStart() {
  super.onStart();
}

//  @@@@@@@@@@@@
void onPause(){
  super.onPause();
  if(snd!=null){
 
    snd.release();
    snd= null;
  }
}

//  @@@@@@@@@@@@
void onStop(){
  super.onStop();
  if(snd!=null){
 
    snd.release();
    snd= null;
  }
 
}
 
//  @@@@@@@@@@@@ 
void onDestroy(){
   super.onDestroy();
  if(snd!=null){
 
    snd.release();
    snd= null;
  }
}

I have also tested the following code which is in the same link above. It uses ketai and the cassette library, which you need to installed via the Contribution manager. Sound files need to be place in a folder named sound which is placed inside the data folder.

Kf

import ketai.sensors.*;
import android.os.Bundle;

import android.os.Environment;
import cassette.audiofiles.SoundFile; 


import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;


int globalProxCtr=0;

int seln=1;
int CM_STD_WAIT=100;
int holdCtr=0;//CM_STD_WAIT;


SoundFile music; 
Boolean isPlaying=false;
int fileN;

// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@


void settings() {
  fullScreen();
}


void setup() {  

  selectionUpdate(1);    

  orientation(LANDSCAPE);  
  stroke(0, 255, 0);
  strokeWeight(2);
  noFill();
  textAlign(CENTER, CENTER);
  textSize(36);
  smooth();
  noStroke();
  frameRate(30);

  rectMode(CORNER);
  ellipseMode(CENTER);
}

// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@


void draw() { 
  background(92);

  if (isPlaying) {
    fill(255, 20, 20);
    //noStroke();
    ellipse(width/2, height/2, width*0.3, height*0.3);
  }

  if (holdCtr>0) {    
    fill(#FFFF00);
    //stroke(0, 255, 0);
    rect(width/2 -100, 0.15*height -15, 100*2, 15*2);
    fill(250, 220, 25);    
    text("Playing a random sound " + fileN + "\nThis message will disappear in "+ int(holdCtr/30), width/2, 0.05*height); 
    holdCtr--;
  }
}


// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@


public void mousePressed() {

  if (isPlaying) {
    music.stop();  
    isPlaying=false;
    holdCtr=0;
  } else {    
    selectionUpdate(int(random(4))+1);
    //music.loop();
    music.play();
    isPlaying=true;

    holdCtr=CM_STD_WAIT;
  }
} 


// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@


void selectionUpdate(int s) {

  String cm_audiofile="sound/default.mp3";  //Default case 
  fileN=s;

  switch(s) {

  case 1:
    cm_audiofile="sound/snd01.amr";
    break;

  case 2:
    cm_audiofile="sound/snd02.amr"; 
    break;

  case 3:
    cm_audiofile="sound/snd03.amr";     
    break;

  case 4:
    cm_audiofile="sound/button-3.mp3";
    break;
  }

  music = new SoundFile(this, cm_audiofile);
}  

Your example above, slightly changed and tested.

import android.media.MediaPlayer;
import android.content.res.AssetFileDescriptor;
import android.content.Context;
import android.app.Activity;
import android.widget.FrameLayout;
//import android.app.Fragment;
import android.os.Bundle;

import android.os.Environment;
import android.graphics.Color;
import android.widget.Toast;
import android.os.Looper;
import android.view.WindowManager;
import android.os.Bundle;
import android.view.ViewParent;
import android.view.ViewGroup;
import android.view.View;
import android.widget.RelativeLayout;
import android.view.LayoutInflater;
import android.R.string;

Activity act;
Context mC;
MediaPlayer mp;
AssetFileDescriptor afd;

void setup() {
  initPlay();
}

void initPlay(){
  act = this.getActivity();
  mC = act.getApplicationContext();
  try {
    mp = new MediaPlayer();
    //afd = mC.getAssets().openFd("test-sound.mp3");//which is in the data folder
    afd = mC.getAssets().openFd("button-3.mp3");
    println("Successfully loaded audio file");
    mp.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(), afd.getLength());
    //delay(900);
    mp.prepare();
  }
  catch (IllegalArgumentException e) {
    e.printStackTrace();
  }
  catch (IllegalStateException e) {
    e.printStackTrace();
  } 
  catch(IOException e) {
    println("File did not load");
    e.printStackTrace();
  }
  
  mp.start();
};

void draw() {
}

public void pause() {
  super.pause();
  if (mp !=null) {
    mp.release();
    mp = null;
  }
};

public void stop() {
  super.stop();
  if (mp !=null) {
    mp.release();
    mp = null;
  }
};
1 Like

Thanks for your great assistance with helping me on the sounds.

I’ll definitely give them a try and incorporate your suggestions.

And I’ll be sure to format my code properly in the future.

Best wishes,

Gord

Hello kfrajer, hello forum,

I am John56 from Germany near Düssldorf and I just copied your code which I wanted to use with my Galaxy S8+. Since you mentioned that the code has been tested specifically with this phone I hoped it will do so for me. However, the code failed in my case. After loading the sketch in android mode and transfering it, I received the message (red lines on the PC) , telling me that the sound file inside my processing 3 data folder cannot be resolved. Did I miss some point? Are there any permissions one has to give? Thank you in advance for your help John56

PS: Here are the messages from the adroid mode of processing 3

java.io.FileNotFoundException: sample.mp3
at android.content.res.AssetManager.nativeOpenAssetFd(Native Method)
at android.content.res.AssetManager.openFd(AssetManager.java:820)
at processing.test.soundtest.soundtest.setup(soundtest.java:50)
at processing.core.PApplet.handleDraw(PApplet.java:1838)
at processing.core.PSurfaceNone.callDraw(PSurfaceNone.java:476)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:516

1 Like

Hi John:

I was looking at the errors listed in your post and it looks like your sound files may not be in the correct folder in your Processing project.

Please see the attached screen snapshot. My sounds and images are inside a ‘data’ folder inside my android app project folder.

I hope this helps.

Best wishes,

Gord

1 Like

Hi Gord,

Thank you a lot for your help! Actually my input file “sample.mp3” is exactly located in the data folder of the associated Processing sketch. On the PC I have a folder \soundtest. Inside this folder I have:

soundtest.pde
\data

and inside \data there ist the soundfile. So the situation seems like in your example. However, I receive these error messages. :neutral_face:

In contrary, if I use loadStrings(filename) there is no problem with errors and the strings located in filename can be read without trouble. So where is the difference? Sorry, I am quite new to processing and maybe asking trivial questions. Appreciate help. Thanks to everybody!

John

1 Like

@John56 === as i have written and posted (old forum) the first code with assetsManager i am absolutely sure that it works; yet in order to verify i tested it again today using 3 phones (Samsung tablet Android 19, Nexus 10 Android 26, Huawei android 28) and it works in the three cases. Sounds are inside the data folder of the sketch, nothing more, not any permission needed…Global structure is very simple: Processing/thesketchfolder/data/sound (i am using osx so the file delimiter is not the same but it does not matter).

1 Like

Thank you for this message, I will try once more and report on what I got.

@John56 unless you actually want to have all the fine-grained control over Android media settings and permissions it might be worth a shot trying the default Processing Sound library which has much improved Android support out of the box since the new version from last September, without the need to deal with any Android-specific classes. The only shortcomings are that Audio input is not supported yet on Android, and also that sound files are stored and played from RAM, which can become a memory problem depending on your application.

This example sketch should work out of the box on Android: https://processing.org/reference/libraries/sound/SoundFile.html

Hello kevinstadler,

Thank you a lot for this very usefull information. I knew the Soundfile library of processing before, but I did not expect, it supports the android mode too. This saves me lots of time in handling the (quite difficult) android classes.
The problem is that I am 63 years old and my first programming language in use was FORTRAN in the 70-th. In these old pre-internet times we learned nothing about object orientated programming, nothing about constructors and classes nor methods. In addition, as a scientist and teacher I am working more on the application side and thus for me the result counts and not so much the actual programming techniques. Sorry for that.
However, I tried your suggestion and it gives me perfectly what I needed: To play a wave sound from the data - folder on my Galaxy S8.
Next thing is to create a routine that makes a wave file from a given byte array containing the sample values of e.g. a sine wave function. Is there any code arround to adchieve this?

THank you so much John56

Glad to hear it’s working for you!

Indeed there is a dedicated class for reading and writing directly from and to the raw data buffer of a sound, the documentation for it is here: https://processing.org/reference/libraries/sound/AudioSample.html

There is actually a well-documented example sketch that comes with the library which is exactly your use case (manually writing a sine wave), in Processing if you go to File > Examples you will find it there under Libraries > Sound > SoundFile > AudioSampleManipulation

(Just a note for slightly advanced usage, the SoundFile class is actually a subclass of AudioSample, so all of the low-level read() and write() methods can also be used on SoundFiles previously loaded from disk! You can find an example of doing this under Libraries > Sound > SoundFile > JumbleSoundFile)

1 Like