Control de amplitud con VolumeShaper

Puedes usar un VolumeShaper en una app de audio para realizar atenuaciones graduales de inicio, de finalización y de transición; reducciones; y demás transiciones de volumen automatizadas breves. La clase VolumeShaper está disponible en Android 8.0 (API nivel 26) y versiones posteriores.

Puedes llamar a createVolumeShaper() en una instancia de AudioTrack o MediaPlayer para crear un VolumeShaper. VolumeShaper únicamente actúa sobre el audio producido por el AudioTrack o MediaPlayer que lo creó.

VolumeShaper.Configuration

El comportamiento de un VolumeShaper se define por su VolumeShaper.Configuration. La configuración especifica una *curva de volumen, un tipo de interpolación y la duración*.

Curva de volumen

La curva de volumen representa el cambio de amplitud en el tiempo. Se define a partir de un par de arreglos de flotación, x[] e y[], que determinan una serie de puntos de control. Cada par (x, y) representa la duración y el volumen, respectivamente. Los arreglos deben tener una duración equivalente y contener un mínimo de 2 valores y un máximo de 16. (La duración máxima de la curva se define en getMaximumCurvePoints()).

Las coordenadas de tiempo se proporcionan durante el intervalo [0.0, 1.0]. El punto de inicio tiene que ser 0.0; el último, 1.0; y el tiempo se tiene que incrementar de manera monotónica.

Las coordenadas de volumen se especifican en escala lineal durante el intervalo [0.0, 1.0].

Tipo de interpolación

La curva de volumen siempre pasa por los puntos de control especificados. Los valores entre los puntos de control se obtienen mediante un trazado según el tipo de interpolación de la configuración. Existen cuatro constantes para los tipos de interpolación VolumeShaper disponibles:

  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_STEP
  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR
  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC
  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC_MONOTONIC

Duración

Las coordenadas de tiempo especificadas en el intervalo [0.0, 1.0] se escalan a la duración que especifiques en milisegundos. Esto determina la duración real en el tiempo de la curva de volumen cuando el modelador está en funcionamiento y aplica la curva a la salida de audio.

Uso de un VolumeShaper

Cómo crear una configuración

Antes de desarrollar un VolumeShaper, tienes que crear una instancia de VolumeShaper.Configuration. Para hacerlo, usa un VolumeShaper.Configuration.Builder():

Kotlin

    val config: VolumeShaper.Configuration = VolumeShaper.Configuration.Builder()
            .setDuration(3000)
            .setCurve(floatArrayOf(0f, 1f), floatArrayOf(0f, 1f))
            .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
            .build()
    

Java

    VolumeShaper.Configuration config =
      new VolumeShaper.Configuration.Builder()
          .setDuration(3000)
          .setCurve(new float[] {0.f, 1.f}, new float[] {0.f, 1.f})
          .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
          .build();
    

Sin argumentos, el constructor de VolumeShaper.Configuration.Builder muestra un compilador que crea una configuración con las opciones de configuración predeterminadas: INTERPOLATOR_TYPE_CUBIC, de un segundo de duración y sin curva. Tienes que agregar una curva al compilador antes de llamar a build().

El marco de trabajo proporciona constantes para las configuraciones con curvas precompiladas, cada una con una duración de un segundo:

  • VolumeShaper.Configuration.LINEAR_RAMP
  • VolumeShaper.Configuration.CUBIC_RAMP
  • VolumeShaper.Configuration.SINE_RAMP
  • VolumeShaper.Configuration.SCURVE_RAMP

Cómo crear un VolumeShaper

Para crear un VolumeShaper, llama a createVolumeShaper() en una instancia de la clase que corresponda, que pase en un VolumeShaper.Configuration:

Kotlin

    volumeShaper = myMediaPlayer.createVolumeShaper(config)
    volumeShaper = myAudioTrack.createVolumeShaper(config)
    

Java

    volumeShaper = myMediaPlayer.createVolumeShaper(config);
    volumeShaper = myAudioTrack.createVolumeShaper(config);
    

Una sola pista o reproductor de medios puede tener muchos modeladores adjuntos, y puedes controlar cada modelador por separado. Las salidas de todos los modeladores en una pista o reproductor se multiplican juntas. Un VolumeShaper no se puede compartir entre AudioTracks o MediaPlayers, pero puedes usar la misma configuración en las llamadas a createVolumeShaper para compilar modeladores idénticos en varios AudioTracks o MediaPlayers.

Cuando creas el modelador, el primer punto de control (en t = 0) se aplica a la transmisión de audio. Si el volumen inicial no es 1.0 y la app reproduce material en el momento de la creación, es posible que el audio cambie abruptamente de volumen. Lo que se recomienda es comenzar a reproducir audio desde el silencio y usar un VolumeShaper para implementar una atenuación gradual de inicio cuando comience la reproducción. Crea un VolumeShaper que comience con un volumen de 0 y se incremente gradualmente. Por ejemplo:

setCurve(new float[] {0.f, 1.f}, new float[] {0.f, 1.f})
    

Comienza la reproducción y el modelador al mismo tiempo. Esto garantiza que la reproducción comience desde el silencio y que el volumen se incremente hasta el máximo. Este proceso se explica en la próxima sección.

Cómo ejecutar un VolumeShaper

Aunque el nivel de volumen del primer punto de control se aplica a la ruta de audio apenas se crea el modelador, este no avanza por la curva hasta que llamas al método apply() con VolumeShaper.Operation.PLAY. Después de crear el modelador, la primera invocación de apply() tiene que especificar la operación de PLAY a fin de iniciar el modelador. Esto ejecuta la curva desde el primer punto de control hasta el último:

Kotlin

    shaper.apply(VolumeShaper.Operation.PLAY)
    

Java

    shaper.apply(VolumeShaper.Operation.PLAY);
    

Mientras el modelador está en ejecución, puedes emitir llamadas de apply() alternativas que especifiquen las operaciones REVERTIR y REPRODUCIR. Esto cambia la dirección de lectura de los puntos de control cada vez.

El modelador ajusta el volumen de manera continua y pasa por todos los puntos de control hasta que caduca. Esto sucede cuando el modelador alcanza el último punto de control de la curva (para la operación REPRODUCIR) o el primero (en la operación REVERTIR).

Cuando el modelador caduca, el volumen permanece en la última configuración, que puede ser el primer punto de control o el último. Puedes llamar a VolumeShaper.getVolume() para el nivel de volumen actual en cualquier momento.

Después de que caduca el modelador, puedes emitir otra llamada de apply() para ejecutar la curva en la dirección opuesta. Por ejemplo, si el moldeador caducó mientras se ejecutaba PLAY, el próximo apply() tiene que ser REVERSE. Llamar a PLAY después de que PLAY caducó o a REVERSE después de que REVERSE caducó no tiene ningún efecto.

Tienes que alternar las operaciones de PLAY y REVERSE. No hay manera de reproducir una curva desde el primer punto de control hasta el último y, luego, reiniciarlo desde el primer punto de control. Puedes usar el método de replace(), que se describe en la sección siguiente, para reemplazar la curva con una copia de sí misma. Esto restablece el modelador, lo que requiere que la operación de PLAY lo inicie nuevamente.

Cambiar la curva

Usa el método de replace() para cambiar una curva de VolumeShaper. Este método toma una configuración, una operación y un parámetro de unión. Puedes llamar al método de replace() en cualquier momento, mientras el modelador está en ejecución o después de que caduca:

Kotlin

    val newConfig = VolumeShaper.Configuration.Builder()
            .setDuration(1000)
            .setCurve(floatArrayOf(0f, 0.5f), floatArrayOf(0f, 1f))
            .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
            .build()
    val join = true
    shaper.replace(newConfig, VolumeShaper.Operation.PLAY, join)
    

Java

    VolumeShaper.Configuration newConfig =
      new VolumeShaper.Configuration.Builder()
        .setDuration(1000)
        .setCurve(new float[] {0.f, 0.5f}, new float[] {0.f, 1.f})
        .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
        .build();
    boolean join = true;
    shaper.replace(newConfig, VolumeShaper.Operation.PLAY, join);
    

Cuando llamas a replace() mientras el modelador está en ejecución, este deja de cambiar el volumen y permanece en su valor actual. Luego, el modelador intenta iniciar la nueva curva desde el primer punto de control. Esto significa que el argumento de la operación controla si el modelador se ejecuta o no después de la llamada. Especifica PLAY para iniciar la nueva curva de inmediato; especifica REVERSE para dejar el modelador en pausa en el volumen del primer punto de control en la nueva curva. Puedes iniciar el modelador más adelante con apply(VolumeShaper.Operation.PLAY).

Cuando llamas a replace() con join = false, el modelador comienza su curva en el nivel que especificó el primer punto de control. Esto puede provocar una discontinuidad en el volumen. Puedes evitarlo si llamas a replace() con join = true. Esto establece el primer punto de control de la nueva curva en el nivel actual del modelador y ajusta el volumen de todos los puntos de control entre el primero y el último para mantener la forma relativa de la nueva curva (el último punto de control no varía). La operación de ajuste cambia permanentemente los puntos de control en la nueva curva del modelador.

Quitar un VolumeShaper

El sistema se cierra y los elementos no utilizados recopilan un VolumeShaper cuando su AudioTrack o MediaPlayer se retira o deja de estar en uso. Puedes llamar al método de close() en un modelador para destruirlo de inmediato. El sistema quita el modelador de la canalización de audio en unos 20 ms. Ten cuidado al cerrar un VolumeShaper mientras se reproduce el audio. Si el modelador tiene un volumen inferior a 1.0 cuando llamas a close(), el ajuste de volumen del modelador cambia a 1.0. Esto puede provocar un aumento repentino en el volumen.