Control de la amplitud con VolumeShaper

Puedes usar un VolumeShaper en una app de audio para realizar atenuaciones de entrada y salida, atenuaciones de transición, atenuación y otras transiciones de volumen automatizadas breves. La clase VolumeShaper está disponible en Android 8.0 (nivel de API 26) y versiones posteriores.

Para crear un VolumeShaper, llama a createVolumeShaper() en una instancia de AudioTrack o MediaPlayer. VolumeShaper solo 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 interpolador y la duración*.

Curva de volumen

La curva de volumen representa el cambio de amplitud en el tiempo. Se define mediante un par de arreglos de números de punto flotante, x[] e y[], que definen una serie de puntos de control. Cada par (x, y) representa el tiempo y el volumen, respectivamente. Los arrays deben tener la misma longitud y contener entre 2 y 16 valores como mínimo. (La longitud máxima de la curva se define en getMaximumCurvePoints()).

Las coordenadas de tiempo se proporcionan durante el intervalo [0.0, 1.0]. El primer punto de tiempo debe ser 0.0, el último debe ser 1.0 y los tiempos deben aumentar de forma 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 derivan mediante un trazado según el tipo de interpolador de la configuración. Hay cuatro constantes para los tipos de interpolador 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 una duración que especifiques en milisegundos. Esto determina la duración real en el tiempo de la curva de volumen cuando el modelador se está ejecutando 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 ello, 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();

With no arguments the VolumeShaper.Configuration.Builder constructor returns a builder that creates a configuration with default settings: INTERPOLATOR_TYPE_CUBIC, a one second duration, and no curve. You must add a curve to the builder before calling build().

The framework provides constants for configurations with pre-built curves, each with one second duration:

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

Creating a VolumeShaper

To create a VolumeShaper, call createVolumeShaper() on an instance of the appropriate class, passing in a VolumeShaper.Configuration:

Kotlin

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

Java

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

A single track or media player can have many shapers attached to it, and you can control each shaper separately. The outputs of all the shapers on a track or player are multiplied together. A VolumeShaper cannot be shared between AudioTracks or MediaPlayers, but you can use the same configuration in calls to createVolumeShaper to build identical shapers on multiple AudioTracks or MediaPlayers.

When you create the shaper, its first control point (at t = 0) is applied to the audio stream. If the initial volume is not 1.0 and your app is playing material at create time, your audio might have an abrupt change in volume. Best practice is to start playing audio from silence and use a VolumeShaper to implement a fade-in when playback starts. Create a VolumeShaper that starts at 0 volume and fades up. For example:

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

Comienza la reproducción y el modelador al mismo tiempo. De esta manera, se garantiza que la reproducción comience desde el silencio y que el volumen se aumente al máximo. Esto se explica en la siguiente sección.

Cómo ejecutar un VolumeShaper

Si bien el nivel de volumen del primer punto de control se aplica a la ruta de audio en cuanto se crea el modelador, este no avanza a lo largo de 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() debe especificar la operación PLAY para iniciar el modelador. Esto ejecuta la curva desde el primer al último punto de control:

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 (para la operación REPRODUCIR) o el primero (para la operación REVERTIR) de la curva.

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

Una vez que caduca el modelador, puedes emitir otra llamada de apply() para ejecutar la curva en la dirección opuesta. Por ejemplo, si el modelador venció mientras se ejecutaba PLAY, el siguiente apply() debe 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 forma de reproducir una curva desde el primer punto de control hasta el último y, luego, reiniciarla nuevamente desde el primer punto de control. Puedes usar el método replace(), que se describe en la siguiente sección, para reemplazar la curva con una copia de sí misma. Esto restablece el modelador y requiere que la operación PLAY lo inicie de nuevo.

Cambiar la curva

Usa el método de replace() para cambiar una curva de VolumeShaper. que toma una configuración, una operación y un parámetro de unión. Puedes llamar al método 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.

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 boolean,TYPE_LINEAR)
Unirse

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, y 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 especificado por el primer punto de control. Esto puede causar una discontinuidad en el volumen. Puedes evitarlo si llamas a replace() con join = true. De esta manera, se establece el primer punto de control de la nueva curva en el nivel actual del modelador y se escala 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 cambia). La operación de escalamiento cambia de forma permanente los puntos de control en la nueva curva del modelador.

Quitar un VolumeShaper

El sistema se cierra y los elementos no utilizados recolectan un VolumeShaper cuando su AudioTrack o MediaPlayer se libera o deja de estar en uso. Puedes llamar al método 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(), la escala de volumen del modelador cambia a 1.0. Esto puede causar un aumento repentino en el volumen.