使用 VolumeShaper 控制振幅

您可以在音频应用程序中使用 VolumeShaper 来执行淡入、淡出、交叉淡入淡出、回避和其他简短的自动音量过渡。 VolumeShaper 类在 Android 8.0(API 级别 26)及更高版本中可用。

可以通过在 AudioTrackMediaPlayer 实例上调用 createVolumeShaper() 创建 VolumeShaperVolumeShaper 仅作用于创建它的 AudioTrack 或 MediaPlayer 生成的音频。

VolumeShaper.Configuration

VolumeShaper 的行为由其 VolumeShaper.Configuration 定义。配置指定了 *音量曲线、插值器类型* 和 *持续时间*。

音量曲线

音量曲线表示音量随时间的变化。它由一对浮点数数组 x[] 和 y[] 定义,这些数组定义了一系列控制点。每个 (x, y) 对分别表示时间和音量。数组必须长度相等,并且至少包含 2 个值,最多包含 16 个值。(最大曲线长度在 getMaximumCurvePoints() 中定义。)

时间坐标在区间 [0.0, 1.0] 内给出。第一个时间点必须为 0.0,最后一个时间点必须为 1.0,并且时间必须单调递增。

音量坐标在区间 [0.0, 1.0] 内以线性刻度指定。

插值器类型

音量曲线始终经过指定的控制点。控制点之间值的推导是根据配置的插值器类型进行样条插值的。有四个常量对应于可用的 VolumeShaper 插值器类型

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

持续时间

区间 [0.0, 1.0] 中指定的“时间”坐标会按您以毫秒为单位指定的持续时间进行缩放。这将确定 shaper 运行时音量曲线应用于音频输出的实际时长。

使用 VolumeShaper

创建配置

在构建 VolumeShaper 之前,您必须创建 VolumeShaper.Configuration 的实例。请使用 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();

在没有参数的情况下,VolumeShaper.Configuration.Builder 构造函数将返回一个构建器,该构建器将创建具有默认设置的配置:INTERPOLATOR_TYPE_CUBIC、一秒钟的持续时间和没有曲线。您必须在调用 build() 之前将曲线添加到构建器中。

框架提供了一些常量,这些常量用于具有预构建曲线的配置,每条曲线都有一秒钟的持续时间

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

创建 VolumeShaper

若要创建 VolumeShaper,请在适当类的实例上调用 createVolumeShaper(),并将 VolumeShaper.Configuration 传递给它

Kotlin

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

Java

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

单个轨道或媒体播放器可以附加多个 shaper,并且可以分别控制每个 shaper。轨道或播放器上所有 shaper 的输出将相乘。 VolumeShaper 无法在 AudioTracksMediaPlayers 之间共享,但可以在对 createVolumeShaper 的调用中使用相同的配置来在多个 AudioTracksMediaPlayers 上构建相同的 shaper。

创建 shaper 时,其第一个控制点(在 t = 0 时)将应用于音频流。如果初始音量不是 1.0,并且您的应用在创建时正在播放素材,则音频的音量可能会发生突然变化。最佳做法是从静音开始播放音频,并在播放开始时使用 VolumeShaper 来实现淡入效果。创建从 0 音量开始并淡入的 VolumeShaper。例如

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

同时开始播放和 shaper。这将确保播放从静音开始,并且音量逐渐增加到最大音量。下一节将对此进行解释。

运行 VolumeShaper

虽然第一个控制点的音量级别会在创建 shaper 后立即应用于音频路径,但 shaper 不会沿着曲线前进,直到您使用 VolumeShaper.Operation.PLAY 调用 apply() 方法。创建 shaper 后,必须在第一次调用 apply() 时指定 PLAY 操作以启动 shaper。这将从第一个控制点运行到最后一个控制点

Kotlin

shaper.apply(VolumeShaper.Operation.PLAY)

Java

shaper.apply(VolumeShaper.Operation.PLAY);

在 shaper 运行期间,您可以发出交替的 apply() 调用,并指定 REVERSE 和 PLAY 操作。这将每次更改控制点读取的方向。

shaper 将持续调整音量,并经过所有控制点,直到 *过期*。当 shaper 达到曲线中的最后一个控制点(对于 PLAY 操作)或第一个控制点(对于 REVERSE 操作)时,就会发生这种情况。

shaper 过期后,音量将保持在最后一个设置,这可能是第一个或最后一个控制点。您可以随时调用 VolumeShaper.getVolume() 来获取当前的音量级别。

shaper 过期后,您可以发出另一个 apply() 调用以相反方向运行曲线。例如,如果 shaper 在运行 PLAY 时过期,则下一个 apply() 必须为 REVERSE。在 PLAY 过期后调用 PLAY,或者在 REVERSE 过期后调用 REVERSE 将不起作用。

您必须交替使用 PLAYREVERSE 操作。无法从第一个控制点到最后一个控制点播放曲线,然后从第一个控制点重新开始。可以使用下一节中描述的 replace() 方法用曲线的副本替换曲线。这将重置 shaper,需要 PLAY 操作才能重新启动。

更改曲线

使用 replace() 方法更改 VolumeShaper 的曲线。此方法接受配置、操作和连接参数。您可以在任何时间调用 replace() 方法,无论 shaper 正在运行还是已过期

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);

在 shaper 运行时调用 replace() 时,它将停止更改音量,并保持在当前值。然后,shaper 将尝试从第一个控制点开始新曲线。这意味着操作参数将控制 shaper 在调用后是否运行。指定 PLAY 以立即启动新曲线,指定 REVERSE 将 shaper 暂停在新曲线的第一个控制点的音量上。您可以稍后使用 apply(VolumeShaper.Operation.PLAY) 启动 shaper。

在使用 join = false 调用 replace() 时,shaper 将从其第一个控制点指定的级别开始其曲线。这会导致音量发生不连续性。您可以通过使用 join = true 调用 replace() 来避免这种情况。这会将新曲线的第一个控制点设置为 shaper 的当前级别,并缩放第一个控制点和最后一个控制点之间的所有控制点的音量以保持新曲线的相对形状(最后一个控制点保持不变)。缩放操作会永久更改 shaper 的新曲线中的控制点。

删除 VolumeShaper

VolumeShaperAudioTrackMediaPlayer 被释放或不再使用时,系统会关闭并垃圾回收它。您可以对 shaper 调用 close() 方法以立即销毁它。系统会在大约 20 毫秒内将 shaper 从音频管道中删除。在音频播放时关闭 VolumeShaper 时要小心。如果在调用 close() 时 shaper 的音量小于 1.0,则 shaper 的音量缩放比例将变为 1.0。这会导致音量突然增加。