2011-03-05 11 views
21

Tengo un archivo .wav que me gustaría usar en mi juego, actualmente estoy cargando el sonido en onCreate() de cada actividad en el juego.Muestra de Soundpool no lista

soundCount = soundpool.load(this,R.raw.count, 1); 

El sonido se reproducirá una vez que comience la actividad.

soundpool.play(soundCount, 0.9f, 0.9f, 1, -1, 1f); 

El problema es que a veces voy a golpear el error "sample x not ready". ¿Es posible cargar el archivo .wav una vez que inicias el juego, lo guardas en la memoria y lo usas luego en el juego? ¿O es posible esperar entre 1 y 2 segundos para que termine el sonido?

Respuesta

32

Deberás esperar a que termine agregando un oyente a través del SoundPool.setOnLoadCompleteListener.

+7

Desafortunadamente, setOnLoadCompleteListener no está disponible antes de API 8 :(¿Hay alguna otra solución conocida para resolver esto utilizando además setOnLoadCompleteListener?/Gracias – SteD

5

Como mi proyecto es compatible con Android 1.5 y no pude usar setOnLoadCompleteListener, resolví retrasar la reproducción del sonido. Mi código fuente de la siguiente manera:

playSound_Delayed(soundId, 100); 

// (..)

private void playSound_Delayed (final int soundId, final long millisec) { 
    // TIMER 
    final Handler mHandler = new Handler(); 
    final Runnable mDelayedTimeTask = new Runnable() { 
    int counter = 0; 
    public void run() { 
     counter++; 

     if (counter == 1) { 
      boolean ret = mHandler.postDelayed(this, millisec); 
      if (ret==false) Log.w("playSound_Delayed", "mHandler.postAtTime FAILED!"); 
     } else { 
      playSound(soundId); 
     } 
    } 
    }; 
    mDelayedTimeTask.run(); 
} 
+1

no exactamente en el tema, pero es posible que desee sustituir System.err .println con Log.w para mostrarlo en LogCat – superjos

+1

System.err.println aparece en logcat con la etiqueta System.err, en realidad. Pero estoy de acuerdo con que Log.w es más limpio – entropy

2

La biblioteca soundpool utiliza el servicio MediaPlayer para decodificar el audio en un mono o estéreo PCM corriente 16 bits prima que nos simplemente puede llamar a la preparación de Stream, que toma algunas veces dependiendo del tamaño del archivo de sonido. Y si tratamos de reproducir el sonido antes de que el proceso termine, obtenemos el error "muestra x no lista".

Hay dos soluciones para este

  1. implementan setOnLoadCompleteListener o
  2. wait cantidad arbitraria de tiempo por lo que la preparación es más

y luego reproducirlo Tenga en cuenta que no hay ninguna excepción para esta condición o aplicación no se bloquea sin try-catch

4

debe usar setOnLoadComplet eListener si es posible ... si no, enrolle un ciclo while alrededor de su llamada para 'reproducir'. algo como:

int waitLimit = 1000; 
int waitCounter = 0; 
int throttle = 10; 
while(soundPool.play(soundId, 1.f, 1.f, 1, 0, 1.f) == 0 && waitCounter < waitLimit) 
{waitCounter++; SystemClock.sleep(throttle);} 

esto volverá a intentar "reproducir" 1000 veces en un intervalo de 10 ms. esto debería ejecutarse en un hilo que no sea ui, por supuesto, y aún no es ideal. pero tal vez un poco más fuerte que esperar un tiempo arbitrario y esperar que el grupo esté listo.

1

Esto suena loco, pero no reproduce sonidos de inmediato. Dale a tu aplicación un par de segundos para inicializar SoundPool. En mi aplicación, este era exactamente el problema; Agregué una pantalla de "carga" falsa de ~ 3 segundos, y luego todo funcionó. (Ni siquiera necesité precargar los sonidos.)

+0

Eso es lo que estoy haciendo pero me parece realmente molesto. El juego se carga en un segundo. La pantalla de carga solo está ahí por el bien de los sonidos. –

+0

@WKS también. Tuve la idea de hacer que la pantalla de carga sea un mini-juego o poner un poco de interactividad en ella como un ki de "huevo de Pascua" nda cosa, a pesar de que solo es visible por un par de segundos. – ashes999

2
private SoundPool soundPool; 
private int my_sound; 
boolean loaded = false; 

// En el constructor

soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0); 
my_sound = soundPool.load(this, R.raw.blast_sound, 1); 

soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() { 
    public void onLoadComplete(SoundPool soundPool, int sampleId,int status) { 
     loaded = true; 
    } 
}); 

// continuación, donde cada vez que desea reproducir el sonido, el tipo

if (loaded) { 
soundPool.play(my_sound, 0.9f, 0.9f, 1, 0, 1f); 
} 
2

he resuelto con un problema con un simple ciclo do-while . El método play() devuelve un streamID distinto de cero si tiene éxito, cero si falla. Por lo tanto, es suficiente para verificar el valor de retorno.

int streamID = -1; 
do { 
    streamID = soundPool.play(soundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f); 
} while(streamID==0); 
2

Esto funcionaría para usted, sin duda!

public void playWavFile() { 

    Thread streamThread = new Thread(new Runnable() {   

     @Override 
     public void run() {     
      SoundPool soundPool; 
      final int wav; 
      String path = "/mnt/sdcard/AudioRecorder/record.wav"; 
      soundPool = new SoundPool(5,AudioManager.STREAM_MUSIC, 0); 
      wav = soundPool.load(path, 1); 
      soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() { 
       @Override 
       public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 
        // TODO Auto-generated method stub 
        soundPool.play(wav,100, 100, 0, 0, 1f); 
       } 
      }); 

     }   
    }); 

    streamThread.start(); 
}