您可以在音频应用中使用 VolumeShaper
来执行淡入、淡出、交叉淡入淡出、背景音降低和其他短时自动音量转换。VolumeShaper
类在 Android 8.0 (API 级别 26) 及更高版本中可用。
您可以通过在 AudioTrack
或 MediaPlayer
实例上调用 createVolumeShaper()
来创建 VolumeShaper
。VolumeShaper
仅对其创建的 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
不能在 AudioTracks
或 MediaPlayers
之间 共享, 但您可以 在调用 createVolumeShaper
时使用 相同的 配置 来 在多个 AudioTracks
或 MediaPlayers
上 构建 相同的 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
将无效。
您必须交替使用 PLAY
和 REVERSE
操作。无法将曲线从第一个控制点播放到最后一个控制点,然后再次从第一个控制点重新开始。您可以使用下一节中描述的 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。
当您调用 replace()
并将 join = false
时,shaper 会在其第一个控制点指定的级别开始其曲线。这可能会导致音量出现不连续性。您可以通过调用 replace()
并将 join = true
来避免这种情况。这将新曲线的第一个控制点设置为 shaper 的当前级别,并缩放第一个和最后一个控制点之间所有控制点的音量,以保持新曲线的相对形状(最后一个控制点不变)。缩放操作会永久改变 shaper 新曲线中的控制点。
移除 VolumeShaper
当 VolumeShaper
的 AudioTrack
或 MediaPlayer
被释放或不再使用时,系统会关闭并垃圾回收它。您可以调用 shaper 上的 close()
方法立即销毁它。系统会在大约 20 毫秒内将 shaper 从音频管道中移除。在音频播放时关闭 VolumeShaper
时要小心。如果 shaper 在您调用 close()
时音量小于 1.0,shaper 的音量缩放将变为 1.0。这可能会导致音量突然增大。