Controllare l'ampiezza con VolumeShaper

Puoi usare un VolumeShaper in un'app audio per eseguire dissolvenze in entrata, in uscita, incrociate, attenuazione automatica e altre brevi transizioni di volume automatiche. La classe VolumeShaper è disponibile in Android 8.0 (livello API 26) e versioni successive.

Puoi creare un VolumeShaper chiamando createVolumeShaper() su un'istanza di AudioTrack o MediaPlayer. VolumeShaper agisce solo sull'audio prodotto dall'AudioTrack o da MediaPlayer che l'ha creato.

VolumeShaper.Configuration

Il comportamento di un elemento VolumeShaper è definito dal suo VolumeShaper.Configuration. La configurazione specifica una *curva volume, il tipo di interpolatore e la durata.*

Curva del volume

La curva del volume rappresenta la variazione di ampiezza nel tempo. È definito da una coppia di array di numeri in virgola mobile, x[] e y[], che definiscono una serie di punti di controllo. Ogni coppia (x, y) rappresenta rispettivamente il tempo e il volume. Gli array devono avere la stessa lunghezza e contenere da 2 a 16 valori. (La lunghezza massima della curva è definita in getMaximumCurvePoints()).

Le coordinate temporali sono date sull'intervallo [0,0, 1,0]. Il primo punto temporale deve essere 0,0, l'ultimo deve essere 1,0 e i tempi devono essere monotonicamente crescenti.

Le coordinate del volume sono specificate in scala lineare sull'intervallo [0,0, 1,0].

Tipo di interpolatore

La curva del volume passa sempre attraverso i punti di controllo specificati. I valori tra i punti di controllo vengono derivati da una spline secondo il tipo di interpolatore della configurazione. Esistono quattro costanti per i tipi di interpolatori VolumeShaper disponibili:

  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_STEP
  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR
  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBI
  • VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBI_MONOTONIC

Durata

Le coordinate di tempo specificate nell'intervallo [0,0, 1,0] vengono ridimensionate su una durata specificata in millisecondi. Questo determina la lunghezza effettiva nel tempo della curva del volume quando lo shaper è in esecuzione e applica la curva all'output audio.

Utilizzo di VolumeShaper

Creazione di una configurazione

Prima di creare un'istanza VolumeShaper, devi creare un'istanza di VolumeShaper.Configuration. A tale scopo, utilizza 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})

Avvia la riproduzione e lo shaper contemporaneamente. In questo modo la riproduzione inizia dal silenzio e il volume aumenta al massimo. Questa procedura viene spiegata nella sezione successiva.

Esecuzione di un VolumeShaper

Anche se il livello del volume del primo punto di controllo viene applicato al percorso audio non appena viene creato lo shaper, questo non avanza lungo la curva finché non chiami il metodo apply() con VolumeShaper.Operation.PLAY. Dopo aver creato lo shaper, la prima chiamata a apply() deve specificare l'operazione PLAY per poter avviare lo shaper. Questo esegue la curva dal primo all'ultimo punto di controllo:

Kotlin

shaper.apply(VolumeShaper.Operation.PLAY)

Java

shaper.apply(VolumeShaper.Operation.PLAY);

Mentre lo shaper è in esecuzione, puoi effettuare chiamate apply() alternate per specificare le operazioni REVERSE e PLAY. Questo modifica ogni volta la direzione di lettura dei punti di controllo.

Lo sagomatore regola continuamente il volume e passa attraverso tutti i punti di controllo fino alla sua scadenza. Questo accade quando lo shaper raggiunge l'ultimo (per l'operazione PLAY) o il primo (per l'operazione INDIETRO) nella curva.

Quando lo shaper scade, il volume rimane all'ultima impostazione, che potrebbe essere il primo o l'ultimo punto di controllo. Puoi chiamare VolumeShaper.getVolume() in qualsiasi momento per conoscere il livello di volume attuale.

Dopo la scadenza dello shaper, puoi effettuare un'altra chiamata apply() per eseguire la curva nella direzione opposta. Ad esempio, se lo shaper è scaduto durante l'esecuzione di PLAY, il valore di apply() successivo deve essere REVERSE. Chiamare PLAY dopo la scadenza di PLAY o la chiamata a REVERSE dopo la scadenza di REVERSE non ha alcun effetto.

Devi alternare le operazioni PLAY e REVERSE. Non c'è modo di riprodurre una curva dal primo all'ultimo punto di controllo e poi riavviarla dal primo punto di controllo. Puoi utilizzare il metodo replace(), descritto nella sezione successiva, per sostituire la curva con una copia di se stessa. Questa operazione reimposta lo shaper, richiedendo l'operazione PLAY per riavviarlo.

Cambiare la curva

Usa il metodo replace() per modificare la curva di VolumeShaper. Questo metodo prevede una configurazione, un'operazione e un parametro di join. Puoi chiamare il metodo replace() in qualsiasi momento, mentre lo shaper è in esecuzione o dopo la sua scadenza:

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_TYPE.buildType()
join Formshar.

Quando chiami replace() mentre lo shaper è in esecuzione, quest'ultimo smette di modificare il volume e rimane al suo valore corrente. Quindi, lo modellatore prova ad avviare la nuova curva dal primo punto di controllo. Ciò significa che l'argomento dell'operazione controlla se lo shaper viene eseguito o meno dopo la chiamata. Specifica PLAY per avviare immediatamente la nuova curva, specifica REVERSE per lasciare lo shaper in pausa al volume del primo punto di controllo nella nuova curva. Puoi avviare lo sagomatore in un secondo momento con apply(VolumeShaper.Operation.PLAY).

Quando chiami replace() con join = false, lo shaper avvia la curva al livello specificato dal primo punto di controllo. Questo può causare una discontinuità del volume. Per evitarlo, chiama replace() al numero join = true. Questo imposta il primo punto di controllo della nuova curva sul livello attuale dello shaper e scala il volume di tutti i punti di controllo tra il primo e l'ultimo per mantenere la forma relativa della nuova curva (l'ultimo punto di controllo è invariato). L'operazione di scalabilità cambia definitivamente i punti di controllo nella nuova curva dello strumento di scalabilità.

Rimozione di un VolumeShaper

Il sistema si chiude e la garbage raccoglie un VolumeShaper quando il relativo AudioTrack o MediaPlayer viene rilasciato o non è più in uso. Puoi chiamare il metodo close() su uno shaper per distruggerlo immediatamente. Il sistema rimuove lo shaper dalla pipeline audio entro circa 20 ms. Fai attenzione quando chiudi un VolumeShaper durante la riproduzione dell'audio. Se il volume dello shaper è inferiore a 1,0 quando chiami close(), la scala del volume dello shaper diventa 1,0. Questo può causare un improvviso aumento del volume.