Loading...
Logo
Processing Forum
I'm attempting to work with Android's SoundPool() in Processing. The two separate files below are in the same Processing project. I can either use the Processing IDE itself or ant to compile and install them to my phone but soundPool.play() doesn't seem to work properly either way - no sounds are played and it returns a zero, which indicates a failure. I followed this example:  http://www.droidnova.com/creating-sound-effects-in-android-part-1,570.html. I've played with MediaPlayer() as well but still no sound is played. 

I've searched but couldn't find a solution for soundPool.play() returning a zero. Has anyone had any success with either soundPool() or MediaPlayer() in Processing for Android?

I have yet to try the Pd libraries for Android but that is next on the list.

Much thanks,
Gary


Here is my file soundPool.java (exported from a .pde)

Copy code
  1. package processing.android.test.soundpool;

  2. import processing.core.*; 
  3. import processing.xml.*; 

  4. import android.content.pm.ActivityInfo; 
  5. import android.os.Handler; 
  6. import android.app.Activity; 
  7. import android.os.Bundle; 
  8. import android.os.Message; 
  9. import android.os.Process; 
  10. import android.content.Context; 
  11. import android.media.SoundPool; 
  12. import android.media.MediaPlayer; 
  13. import android.media.AudioManager; 
  14. import android.media.AudioFormat; 

  15. import android.view.MotionEvent; 
  16. import android.view.KeyEvent; 
  17. import android.graphics.Bitmap; 
  18. import java.io.*; 
  19. import java.util.*; 

  20. public class soundPool extends PApplet {

  21. // Declarations
  22. int counter = 0;
  23. int SoundInt = 0;
  24. SoundPoolSoundManager s;

  25. public void setup(){
  26.   background(255);
  27.   
  28.   // Volume controls will be used for audio, not ringer volume.
  29.   setVolumeControlStream(AudioManager.STREAM_MUSIC);   
  30.   
  31.   s = new SoundPoolSoundManager(this);
  32.   s.init();            // Initialize soundPool before using it.
  33. }

  34. public void draw(){
  35.   counter = counter + 1;               // Increment counter
  36.     
  37.   print("Time = " + counter + "s");    // Print some info so we know we're running
  38.   delay(1000);                         // Wait 1s.
  39.   
  40.   if (counter == 6){                    // Imposes 6s delay.
  41.   s.playSound(1);
  42.   print("playsound");
  43.   }
  44. }

  45.   public int sketchWidth() { return 480; }
  46.   public int sketchHeight() { return 800; }
  47.   public String sketchRenderer() { return A3D; }
  48. }



Here is my SoundPoolManager.java file:
Copy code
  1. package processing.android.test.soundpool;
  2. import android.content.pm.ActivityInfo;
  3. import android.os.Handler;
  4. import android.app.Activity;
  5. import android.os.Bundle;               
  6. import android.os.Message; 
  7. import android.os.Process;
  8. import android.content.Context;

  9. import android.media.SoundPool;
  10. import android.media.MediaPlayer;
  11. import android.media.AudioManager;
  12. import android.media.AudioFormat;

  13. import processing.core.*;
  14. import processing.xml.*; 
  15. import java.io.*;
  16. import java.util.*;
  17. import java.text.*;
  18. import java.lang.Object;

  19. import java.util.ArrayList; // May not be needed
  20. import java.util.List;
  21. //public class SoundPoolSoundManager implements SoundManager{      // Erro: SoundManager not found
  22. public class SoundPoolSoundManager{                    // Can I declare class without SoundManager?
  23.   // Following http://www.droidnova.com/creating-sound-effects-in-android-part-1,570.html
  24. // Class Declarations:
  25. private SoundPool soundPool;                      
  26. private HashMap<Integer, Integer> soundPoolMap; // Use a HashMap to organize image files
  27. private Context context;

  28. private int soundId;
  29. public SoundPoolSoundManager(Context context){
  30. this.context = context;
  31. }
  32. // Initialize soundPool:
  33. public void init() {
  34. if (soundPool != null) {
  35. soundPool.release();
  36. soundPool = null;
  37. }
  38. // Initialize soundPool:
  39. //                          max streams, stream type, source quality
  40. soundPool = new SoundPool(24, AudioManager.STREAM_MUSIC, 0);
  41. soundPoolMap = new HashMap<Integer, Integer>();
  42.                // Commented this out since I load the resource below during playSound.
  43.               //soundPoolMap.put(1, soundPool.load(this.context, R.raw.applewav, 1));  
  44. }

  45. public void playSound(int sound) {
  46.         int soundInt = 1;                               // Set this to non-zero for now.
  47. if (soundPool != null){             // Check if soundPool is alive.
  48. AudioManager mgr = (AudioManager)                                             
  49. context.getSystemService(Context.AUDIO_SERVICE);   

  50.                         // See http://www.droidnova.com/creating-sound-effects-in-android-part-1,570.html
  51. float streamVolume = mgr.getStreamVolume(AudioManager.STREAM_MUSIC); 
  52.                         streamVolume = streamVolume / mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 
  53.                         //soundId = soundPoolMap.get(sound);
  54.                         soundId = soundPool.load(this.context, R.raw.applewav, 1);

  55.                         // soundID, left volume, right volume, priority, loop, playback rate
  56.                         soundInt = soundPool.play(soundId, streamVolume, streamVolume, 1, 0, 1f);
  57.             }
  58.       }      
  59. }




Replies(6)

Success!! I needed to change the code so that the setup/init occurred during onCreate(), as follows. I just placed this code at the end of my .pde (i.e. inside public class soundPool extends PApplet{...} ).  I hope this helps others... 

The only remaining issue is there is a slight click when the sound clip is done playing.

Copy code
  1. @Override
  2. public void onCreate(Bundle savedInstanceState){
  3.   super.onCreate(savedInstanceState);
  4.   // Do sound initializations here...
  5.   s = new SoundPoolSoundManager(this);
  6.   s.init();            // Initialize soundPool before using it.  
  7. }
Nice!

I have a question. In which folder do you place the sound files? Data folder?


A tip about the initializations having to be in onCreate:

Activity has a method for running stuff in the ui-thread.

Im guessing this would also work:

Copy code
  1. runOnUiThread(new Runnable()
            {
                public void run(){
                   
  2.               // Do sound initializations here...
  3.               s = new SoundPoolSoundManager(this);
  4.               s.init();      
  5.             }
            }); 



Good question... I actually had to export my .pde project to get the R.raw.applewav to load properly. Then create a folder named raw inside of the res folder. So the following line of code...
Copy code
  1. soundId = soundPool.load(this.context, R.raw.applewav, 1);

...might be replaced by...
Copy code
  1. soundId = soundPool.load("applewav.wav", 1);

The SoundPool() load method is described here. The way it's used in the second line of code is by inputting a path and priority (i.e. load (String path, int priority) ).

I actually had to export my .pde project to get the R.raw.applewav to load properly. Then create a folder named raw inside of the res folder. So the following line of code...

I was a little afraid of that since I've had problems with MediaPlayer and VideoView not being allowed to load from the assets folder.

...might be replaced by...
Copy code
Copy code
  1. soundId = soundPool.load("applewav.wav", 1);

 
Are you saying that SoundPool may be allowed to access the assets-folder?

Rikard

Yes, I may get around to trying it but if you look at soundPool.load()'s documentation you'll see that there are a few different ways to use load. It might work, might not. 

If you're doing sound, it's not terrible to export your project (now you have .java files), code in any old editor and compile/debug it using ant.
I managed to make Android Processing play sound files placed directly in the data-folder. I made it part of the APWidgets-library that wraps Android widgets like Button, CheckBox, EditText, VideoView, MediaPlayer and more.

It's fairly simple to use PMediaPlayer to play sound files. You have to release the player when the app is destroyed, which happens when you press the back-button, and when you switch orientation betwen landscape and portrait. It would be nice to be able to hide this, but i haven't found a way to capture the onDestroy event any other way.

It's GPL.

Copy code
  1. import apwidgets.*;

    PMediaPlayer player;

    void setup() {

      player
    = new PMediaPlayer(this); //create new PMediaPlayer
      player
    .setMediaFile("test.mp3"); //set the file (files are in data folder)
      player
    .start(); //start play back
      player
    .setLooping(true); //restart playback end reached
      player
    .setVolume(1.0, 1.0); //Set left and right volumes. Range is from 0.0 to 1.0

    }

    void draw() {

      background
    (0); //set black background
      text
    (player.getDuration(), 10, 10); //display the duration of the sound
      text
    (player.getCurrentPosition(), 10, 30); //display how far the sound has played

    }

    void keyPressed() {

     
    if (key == CODED) {
       
    if (keyCode == LEFT) {
          player
    .seekTo(0); //"rewind"
       
    }
       
    else if (keyCode == RIGHT) {
          player
    .start(); //start playing sound file
       
    }
       
    else if (keyCode == DPAD) {
          player
    .pause(); //pause player
       
    }
       
    else if (keyCode == DOWN) {
          player
    .setMediaFile("test2.mp3"); //switch to other sound file
       
    }
     
    }
    }

    //The MediaPlayer must be released when the app closes
    public void onDestroy() {

     
    super.onDestroy(); //call onDestroy on super class
     
    if(player!=null) { //must be checked because or else crash when return from landscape mode
        player
    .release(); //release the player

     
    }
    }