Você pode usar um VolumeShaper
em um app de áudio para realizar
fade-ins, esmaecimentos, cross fades, redução de áudio e outras transições de volume curtas
automatizadas. A classe VolumeShaper
está disponível no Android 8.0 (nível 26 da API)
e versões mais recentes.
Você cria um VolumeShaper
chamando createVolumeShaper()
em uma instância de
AudioTrack
ou MediaPlayer
. O
VolumeShaper
só atua no áudio produzido pelo AudioTrack ou MediaPlayer
que o criou.
VolumeShaper.Configuration
O comportamento de uma VolumeShaper
é definido pelo
VolumeShaper.Configuration
. A configuração especifica uma
*curva de volume, tipo de interpolador e duração.*
Curva de volume
A curva de volume representa a mudança de amplitude ao longo do tempo. Ela é definida por um par de matrizes flutuantes, x[] e y[], que definem uma série de pontos de controle. Cada par (x, y)
representa tempo e volume, respectivamente. As matrizes precisam ter o mesmo comprimento e conter pelo menos 2 e no máximo 16 valores. O comprimento máximo da curva é
definido em getMaximumCurvePoints()
.
As coordenadas de tempo são fornecidas no intervalo [0.0, 1.0]. O primeiro ponto de tempo precisa ser 0,0, o último precisa ser 1,0 e os tempos precisam ser monotonicamente crescentes.
As coordenadas de volume são especificadas em escala linear no intervalo [0.0, 1.0].
Tipo de interpolador
A curva de volume sempre passa pelos pontos de controle especificados. Os valores
entre os pontos de controle são derivados por um spline de acordo com o
tipo de interpolador da configuração. Há quatro constantes para os tipos de interpolador
VolumeShaper
disponíveis:
- VolumeShaper.Configuration.INTERPOLATOR_TYPE_STEP
- VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR
- VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC
- VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC_MONOTONIC
Duração
As coordenadas de tempo especificadas no intervalo [0.0, 1.0] são dimensionadas para uma duração que você especifica em milissegundos. Isso determina a duração real no tempo da curva de volume quando o shaper está em execução e aplicando a curva à saída de áudio.
Usar um VolumeShaper
Criar uma configuração
Antes de criar uma VolumeShaper
, você precisa criar uma instância de VolumeShaper.Configuration
. Faça isso usando um
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})
Inicie a reprodução e o shaper ao mesmo tempo. Isso garante que a reprodução comece a partir do silêncio e que o volume seja carregado para o máximo. Isso é explicado na próxima seção.
Executar um VolumeShaper
Embora o nível de volume do primeiro ponto de controle seja aplicado ao caminho de áudio
assim que o shaper é criado, o shaper não progride ao longo da curva
até que você chame o método apply()
com VolumeShaper.Operation.PLAY
. Depois de criar o shaper, a primeira invocação de apply()
precisa especificar a operação PLAY
para iniciá-lo. Isso executa a curva do primeiro
para o último ponto de controle:
Kotlin
shaper.apply(VolumeShaper.Operation.PLAY)
Java
shaper.apply(VolumeShaper.Operation.PLAY);
Enquanto o shaper estiver em execução, você poderá emitir chamadas apply()
alternadas especificando
as operações REVERSE e PLAY. Isso muda a direção da leitura dos
pontos de controle a cada vez.
O shaper ajusta o volume continuamente e passa por todos os pontos de controle até expirar. Isso acontece quando o shaper chega ao último (para a operação PLAY) ou ao primeiro (para a operação REVERSE) na curva.
Quando o shaper expira, o volume permanece na última configuração, que pode ser
o primeiro ou o último ponto de controle. Você pode chamar VolumeShaper.getVolume()
para
o nível de volume atual a qualquer momento.
Depois que o shaper expirar, você poderá emitir outra chamada apply()
para executar a curva
na direção oposta. Por exemplo, se o shaper expirou durante a execução de
PLAY
, o próximo apply()
precisa ser REVERSE
. Chamar PLAY
depois da expiração de PLAY
ou de REVERSE
depois da expiração de REVERSE
não tem efeito.
Você precisa alternar as operações PLAY
e REVERSE
. Não é possível reproduzir uma
curva do primeiro ao último ponto de controle e, em seguida, reiniciá-la do
primeiro ponto de controle. Você pode usar o método replace()
, descrito na próxima seção, para substituir a curva por uma cópia dela. Isso redefine o shaper,
exigindo que a operação PLAY
o inicie novamente.
Mudar a curva
Use o método replace()
para mudar a curva de um VolumeShaper
. Esse método usa uma configuração, uma operação e um parâmetro de agrupamento. Você pode chamar o
método replace()
a qualquer momento, enquanto o shaper estiver em execução ou depois que ele expirar:
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 = Config.replace, shaper.PLAY,
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_buildTYPE_LINEAR) .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_buildTYPE_LINEAR)
Quando você chama replace()
enquanto o shaper está em execução, ele para de mudar o
volume e permanece no valor atual. Em seguida, o shaper tenta iniciar a nova
curva no primeiro ponto de controle. Isso significa que o argumento de operação controla se o shaper é executado ou não após a chamada. Especifique PLAY
para
iniciar a nova curva imediatamente e REVERSE
para deixar o shaper pausado no
volume do primeiro ponto de controle na nova curva. Você pode iniciar o shaper
mais tarde com apply(VolumeShaper.Operation.PLAY)
.
Quando você chama replace()
com join = false
, o shaper inicia a curva no nível especificado pelo primeiro ponto de controle. Isso pode causar uma descontinuidade
no volume. Você pode evitar isso chamando replace()
com join = true
.
Isso define o primeiro ponto de controle da nova curva para o nível atual do
shaper e dimensiona o volume de todos os pontos de controle entre o primeiro e
o último para manter a forma relativa da nova curva (o último ponto de controle não
é alterado). A operação de dimensionamento muda permanentemente os pontos de controle na
nova curva do shaper.
Remover um VolumeShaper
O sistema é fechado, e o lixo coleta um VolumeShaper
quando a AudioTrack
ou
MediaPlayer
é liberada ou não está mais em uso. Você pode chamar o método close()
em um shaper para destruí-lo imediatamente. O sistema remove o shaper do
pipeline de áudio em cerca de 20 ms. Tenha cuidado ao fechar um VolumeShaper
enquanto o áudio está tocando. Se o shaper tiver um volume menor que 1,0 quando você chamar close()
, a escala de volume do shaper vai mudar para 1,0. Isso pode causar um aumento repentino no volume.