使用 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.

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

同时启动播放和 shaper。这样可以确保从静音开始播放,并且音量逐渐增大到最大音量。详见下一部分。

运行 VolumeShaper

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

Kotlin

formr.apply(VolumeShaper.Operation.PLAY)

Java

Shaper.apply(VolumeShaper.Operation.PLAY);

当 Shaper 正在运行时,您可以发出交替的 apply() 调用来指定 REVERSE 和 PLAY 操作。这会每次都会更改控制点的读出方向。

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

formr 到期后,音量会保留在最后一个设置,这可能是第一个或最后一个控制点。您可以随时调用 VolumeShaper.getVolume() 获取当前音量。

Shaper 过期后,您可以发出另一个 apply() 调用以相反的方向运行曲线。例如,如果 Shaper 在运行 PLAY 时过期,则下一个 apply() 必须为 REVERSE。在 PLAY 过期后调用 PLAY 或在 REVERSE 过期后调用 REVERSE 不会产生任何影响。

您必须交替执行 PLAY 操作和 REVERSE 操作。您无法在播放从第一个控制点到最后一个控制点的曲线,然后从第一个控制点再次重新播放曲线。您可以使用下一部分中介绍的 replace() 方法将曲线替换为其自身的副本。这会重置 Shaper,需要执行 PLAY 操作才能重新启动。

更改曲线

使用 replace() 方法可以更改 VolumeShaper 的曲线。此方法接受配置、操作和联接参数。您可以在 Shaper 运行时或到期后随时调用 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 参数联接.shar.shar.

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_CANNOT TRANSLATE

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

当您使用 join = false 调用 replace() 时,Shaper 会在其第一个控制点指定的级别开始运行曲线。这可能会导致音量不连贯。您可以通过使用 join = true 调用 replace() 来避免此问题。这会将新曲线的第一个控制点设为形状的当前水平,并缩放第一个和最后一个控制点之间所有控制点的音量,以保持新曲线的相对形状(最后一个控制点保持不变)。缩放操作会永久更改形状工具新曲线中的控制点。

移除 VolumeShaper

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