使用 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();

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.

创建 整形器 第一个 控制点 ( t = 0) 应用于 音频流 如果 初始 音量 1.0 并且 您的 应用 正在 播放 素材 创建 您的 音频 可能会 出现 音量 突然 变化 最佳实践 静音 开始 播放音频 并使用 VolumeShaper 实现 淡入- 播放开始 创建 一个 VolumeShaper 0 音量 开始 逐渐增大 例如:

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

同时开始播放和整形器。这确保播放从静音开始,音量逐渐增大到最大音量。这将在下一节中进行解释。

运行 VolumeShaper

尽管第一个控制点的音量级别在整形器创建后立即应用于音频路径,但整形器不会沿着曲线前进,直到您使用 apply() 方法和 VolumeShaper.Operation.PLAY 调用它。在创建整形器后,apply() 的第一次调用必须指定 PLAY 操作才能启动整形器。这会从其第一个到最后一个控制点运行曲线

Kotlin

shaper.apply(VolumeShaper.Operation.PLAY)

Java

shaper.apply(VolumeShaper.Operation.PLAY);

在整形器运行期间,您可以发出交替的 apply() 调用,指定 REVERSE 和 PLAY 操作。这每次都会改变控制点读取的方向。

整形器不断调整音量并穿过所有控制点,直到它过期。当整形器到达曲线中的最后一个(对于 PLAY 操作)或第一个(对于 REVERSE 操作)控制点时,就会发生这种情况。

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

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

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

更改曲线

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

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

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

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

移除 VolumeShaper

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