2011-05-16 20 views
10

Estoy desarrollando una aplicación de metrónomo. El usuario puede seleccionar en tiempo de ejecución los bpm, y mi aplicación reproducirá el sonido "tick" en consecuencia. El "tic" es un solo metrónomo "shot" (mp3). Intenté implementarlo usando Handler y MediaPlayer, pero el metrónomo no es preciso en absoluto. así que pensé en cambiar todo el enfoque: cuando el usuario seleccione un nuevo valor de BPM, sintetizo un nuevo sonido mediante la repetición de los X veces de sonido tic cada N milisegundos, a continuación, un bucle sobre este sonido creado en tiempo de ejecución. ¿Es esta una alternativa válida? ¿Cómo se puede implementar en Android?reproducir un sonido cada N milisegundos

+1

bucle será, de nuevo, crear una demora inexacta. Por lo tanto, debe usar un sonido de metrónomo largo, el más largo, mejor, para evitar o, al menos, minimizar la demora entre reproducciones en el ciclo.Y, a continuación, utilice algún método para hacer frente al retraso introducido, comparando el tiempo actual con el tiempo de ejecución y avanzando hacia adelante el flujo de reproducción para compensar el desplazamiento. –

+1

En realidad, implementé esto a través de AudioTrack y la demora de bucle de la que está hablando no se nota en absoluto. Comparado con un metrónomo real, es de aproximadamente 0.5 bpm, por lo que es definitivamente aceptable. – Raffaele

+1

¿Puede mostrarme algún código sobre cómo lo ha hecho? ¡Estoy bastante interesado! – MartijnG

Respuesta

4

La alternativa de bucle a través de un sonido sintetizado parece ser la mejor opción por el momento. Hubo una gran sesión sobre audio en Google I/O 2013 llamado High Performance Audio que sin duda viendo consejos para tener una comprensión más profunda de cómo funciona el sistema y qué problemas los desarrolladores se enfrentan cuando se trata de la latencia de audio. Aproximadamente a las 17:00 del video, hay un gráfico que muestra jitter frente a devoluciones de llamada. En el mundo perfecto que no existe (¿en serio?), El jitter sería cero para todas las devoluciones programadas de audio realizadas. Pero ese no es el caso, ya que hay temblores de hasta 35 milisegundos o incluso más, ya que los datos en el gráfico se hicieron usando un dispositivo ICS no especificado y ciertamente hay peores escenarios que eso.

lo tanto, como un metrónomo es una herramienta de precisión y estos nervios no son buenos en todo, el enfoque de la reproducción programada se debe dejar a un lado. Incluso hice un metrónomo razonablemente confiable con un sonido sintetizado usando AudioTrack.

creo que sirve ^^

+3

Disculpe si esto es tarde, ¿podría publicar su código donde implementó con éxito un metrónomo utilizando 'AudioTrack'? –

+1

Aquí: http://masterex.github.io/archive/2012/05/28/android-audio-synthesis.html –

1

Puede intentar utilizar un TimerTask programado para la ejecución de tasa fija en un Timer.

temporizador y TimerTask son tanto parte del SDK de Android (y Java SE). Las ejecuciones no se retrasan debido al tiempo de ejecución del evento anterior.

Timer timer = new Timer("MetronomeTimer", true); 
TimerTask tone = new TimerTask(){ 
    @Override 
    public void run(){ 
     //Play sound 
    } 
}; 
timer.scheduleAtFixedRate(tone, 500, 500); //120 BPM. Executes every 500 ms. 

Puede cancelar el TimerTask cuando necesite cambiar los BPM.

tone.cancel(); 
tone = new TimerTask(){...} 
timer.scheduleAtFixedRate(tone, 1000, 1000); //60 BPM. Executes every 1000 ms. 

Otra posibilidad que puede satisfacer sus necesidades (de sus comentarios) está haciendo girar un hilo y la comprobación System.nanoTime() y durmiendo en incrementos pero girando cuando se acerque a despertar.

long delayNanos = 500000000; 
long wakeup = System.nanoTime() + delayNanos; //Half second from right now 
long now; 

while(!done){ 
    now = System.nanoTime(); 

    //If we are less than 50 milliseconds from wake up. Spin away. 
    if(now <= wakeup - 50000000){ 
      //Sleep in very small increments, so we don't spin unrestricted. 

      Thread.sleep(10); 
    } 
    if(now >= wakeup){ 
      //Play sound 
      wakeup += delayNanos; 
    } 
} 
+2

Las implementaciones de subprocesos no son buenas para esta tarea, tanto en el sabor de Java (Timer + TimerTask) como en el de Android (Handler + Message). El tiempo en los móviles es absolutamente malo – Raffaele

+0

Para evitar el problema de granularidad con respecto a las esperas, existe la posibilidad de que haya un hilo que siga funcionando (utilizando Thread.yield()), verificando constantemente el tiempo y despertando el otro hilo. Podría ser una solución. –

+0

@chris ya lo intenté. No resuelve el problema – Raffaele

0

Cuando este sonido juego se llama

mSoundManager.playSound(1); 

espera Android hasta que se termine la llamada, a continuación, se llama a

mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200); 

Sin embargo, si invierte los llamadas, puede encontrar que el tiempo es más preciso.

mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200); 
mSoundManager.playSound(1); 

No se puede contar con su sonido teniendo exactamente la misma cantidad de tiempo para jugar, por lo que dice el manejador de la publicación, en primer lugar es un poco mejor. Todavía no es ideal, sin embargo.

Cuestiones relacionadas